ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Django 中序列化模型实例?

有很多关于如何序列化模型查询集的文档,但是如何将模型实例的字段序列化为 JSON?

虽然看起来您可以序列化 1 个对象的查询集,但您不能使用 django.core 中的类来执行此操作。有什么特别的理由不使用序列化查询集吗?
查询集序列化程序将结果包装在比它必须的多两层中。所以你必须做 data[0].fields.name 而不是 data.name。
我也那么认为。我在为 django 后端编写 GWT 接口时遇到了同样的问题。看起来大卫可能正在做点什么。

M
Michael Allan Jackson

您可以轻松地使用列表来包装所需的对象,这就是 django 序列化程序正确序列化它所需的全部内容,例如:

from django.core import serializers

# assuming obj is a model instance
serialized_obj = serializers.serialize('json', [ obj, ])

但作为响应,您需要索引 JSON 对象的零元素以获取序列化对象。只是需要注意的一点。
以及如何将所有引用的对象与根对象一起序列化?
您不想像@DavorLucic 建议的那样在最后一行末尾添加 [0] 吗?并且不需要在您的列表文字中使用尾随逗号(为了 PEP8 的爱;)。
反序列化还需要一个额外的步骤;见stackoverflow.com/a/29550004/2800876
这对我不起作用。 Django 抛出 AttributeError 'tuple' 对象没有属性 '_meta'
P
Pavel Daynyak

如果您正在处理模型实例列表,那么您可以做的最好的事情就是使用 serializers.serialize(),它会完全满足您的需要。

但是,您将面临尝试序列化 单个 对象而不是 list 对象的问题。这样,为了摆脱不同的 hack,只需使用 Django 的 model_to_dict (如果我没记错的话,serializers.serialize() 也依赖它):

from django.forms.models import model_to_dict

# assuming obj is your model instance
dict_obj = model_to_dict( obj )

您现在只需直接调用 json.dumps 即可将其序列化为 json:

import json
serialized = json.dumps(dict_obj)

而已! :)


这会因 UUID 字段而失败,否则应该清楚
datetime 字段失败。以这种方式解决它 json.loads(serialize('json', [obj]))[0] 而序列化程序是 django.core.serializers.serialize
T
Tim Saylor

为避免使用数组包装器,请在返回响应之前将其移除:

import json
from django.core import serializers

def getObject(request, id):
    obj = MyModel.objects.get(pk=id)
    data = serializers.serialize('json', [obj,])
    struct = json.loads(data)
    data = json.dumps(struct[0])
    return HttpResponse(data, mimetype='application/json')

我也发现了这个有趣的帖子:

http://timsaylor.com/convert-django-model-instances-to-dictionaries

它使用 django.forms.models.model_to_dict,这看起来是完成这项工作的完美工具。


如果这是在 django 中序列化单个模型的最佳方式,那么这太可怕了,因为不需要反序列化 json 并将其序列化回来。
@Herbert,也许。但它就在那里。如果你有更好的方法,我会全力以赴。这不应该有太多实际的缺点,因为获取和解/重新编码单个对象不应该是资源密集型的。如果您想隐藏恐怖,请将其作为辅助功能或与您的对象扩展/混合作为一种新方法。
隐藏恐怖不是问题,甚至可能不是这个解决方案;令我惊讶的是,这是 django 最好的方法。
k
kagronick

对此有一个很好的答案,我很惊讶它没有被提及。只需几行代码,您就可以处理日期、模型和其他所有内容。

制作一个可以处理模型的自定义编码器:

from django.forms import model_to_dict
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Model

class ExtendedEncoder(DjangoJSONEncoder):

    def default(self, o):

        if isinstance(o, Model):
            return model_to_dict(o)

        return super().default(o)

现在在使用 json.dumps 时使用它

json.dumps(data, cls=ExtendedEncoder)

现在模型、日期和所有内容都可以序列化,而不必在数组中或序列化和非序列化。您拥有的任何自定义内容都可以添加到 default 方法中。

你甚至可以通过这种方式使用 Django 的原生 JsonResponse:

from django.http import JsonResponse

JsonResponse(data, encoder=ExtendedEncoder)

这个解决方案简单而优雅。编码器可与 json.dumpsjson.dump 方法一起使用。这样您就不需要更改应用程序的工作流程,因为您使用自定义对象或在转换为 json 之前添加另一个方法调用。只需在编码器中添加您的转换代码,您就可以开始了。
MyModel 类型的对象不是 JSON 可序列化的
@AlxVallejo 您没有添加关于 model_to_dict 的部分,或者您没有正确调用它。
D
David Berger

听起来您要问的内容涉及序列化 Django 模型实例的数据结构以实现互操作性。其他海报是正确的:如果您希望将序列化表单与可以通过 Django 的 api 查询数据库的 python 应用程序一起使用,那么您将希望使用一个对象序列化查询集。另一方面,如果您需要一种在不接触数据库或不使用 Django 的情况下在其他地方重新膨胀模型实例的方法,那么您还有一些工作要做。

这就是我所做的:

首先,我使用 demjson 进行转换。它恰好是我首先发现的,但它可能不是最好的。我的实现取决于其功能之一,但其他转换器应该有类似的方法。

其次,在您可能需要序列化的所有模型上实施 json_equivalent 方法。这是 demjson 的一种神奇方法,但无论您选择哪种实现,它都可能是您需要考虑的事情。这个想法是您返回一个可直接转换为 json 的对象(即数组或字典)。如果您真的想自动执行此操作:

def json_equivalent(self):
    dictionary = {}
    for field in self._meta.get_all_field_names()
        dictionary[field] = self.__getattribute__(field)
    return dictionary

除非您有一个完全扁平的数据结构(没有 ForeignKeys,数据库中只有数字和字符串等),否则这对您没有帮助。否则,您应该认真考虑实施此方法的正确方法。

第三,调用 demjson.JSON.encode(instance),你就得到了你想要的。


我还没有尝试过代码,但我只是想指出其中的一些错误。它是 instance._meta.get_all_field_names(),而 getattribute 是一个函数,所以应该有 () 而不是 []。
除了 FK,这不适用于日期时间字段(除非 demjson.JSON.encode 中有魔法)
f
flowfelis

如果您想将单个模型对象作为 json 响应返回给客户端,您可以执行以下简单的解决方案:

from django.forms.models import model_to_dict
from django.http import JsonResponse

movie = Movie.objects.get(pk=1)
return JsonResponse(model_to_dict(movie))

n
np_6

如果您要询问如何从模型中序列化单个对象,并且您知道您只会在查询集中获取一个对象(例如,使用 objects.get),那么请使用以下内容:

import django.core.serializers
import django.http
import models

def jsonExample(request,poll_id):
    s = django.core.serializers.serialize('json',[models.Poll.objects.get(id=poll_id)])
    # s is a string with [] around it, so strip them off
    o=s.strip("[]")
    return django.http.HttpResponse(o, mimetype="application/json")

这会给你一些形式:

{"pk": 1, "model": "polls.poll", "fields": {"pub_date": "2013-06-27T02:29:38.284Z", "question": "What's up?"}}

但这将去除所有方括号,而不仅仅是外部方括号。更好的? “o=s[1:-1]”?
@Julian str.strip 仅去除外部字符-一切都很好!
n
np_6

.values() 是将模型实例转换为 JSON 所需的。

.values() 文档:https://docs.djangoproject.com/en/3.0/ref/models/querysets/#values

使用名为 Project 的模型的示例用法。

注意:我正在使用 Django Rest 框架

@csrf_exempt
@api_view(["GET"])
def get_project(request):
    id = request.query_params['id']
    data = Project.objects.filter(id=id).values()
    if len(data) == 0:
        return JsonResponse(status=404, data={'message': 'Project with id {} not found.'.format(id)})
    return JsonResponse(data[0])

来自有效 id 的结果:

{
    "id": 47,
    "title": "Project Name",
    "description": "",
    "created_at": "2020-01-21T18:13:49.693Z",
}

d
davidchambers

我通过向我的模型添加序列化方法解决了这个问题:

def toJSON(self):
    import simplejson
    return simplejson.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))

对于那些厌恶单行的人来说,这是冗长的等价物:

def toJSON(self):
    fields = []
    for field in self._meta.fields:
        fields.append(field.name)

    d = {}
    for attr in fields:
        d[attr] = getattr(self, attr)

    import simplejson
    return simplejson.dumps(d)

_meta.fields 是可以从实例和模型本身访问的模型字段的有序列表。


虽然这个想法一开始看起来不错,但应该指出使用这种方法会产生一些后果。您正在将一个特定的序列化输出绑定到您的模型。
@JonasGeiregat,因为这种方法是在模型到模型的基础上定义的,这种方法有什么问题?可悲的是,这似乎是返回包含实例的字段和主键的 json 对象的唯一方法。
D
DanH

这是我的解决方案,它允许您轻松自定义 JSON 以及组织相关记录

首先在模型上实现一个方法。我称它为 json,但您可以随意称呼它,例如:

class Car(Model):
    ...
    def json(self):
        return {
            'manufacturer': self.manufacturer.name,
            'model': self.model,
            'colors': [color.json for color in self.colors.all()],
        }

然后在视图中我这样做:

data = [car.json for car in Car.objects.all()]
return HttpResponse(json.dumps(data), content_type='application/json; charset=UTF-8', status=status)

在 Python 3 中,它变为 car.json()
n
niran

使用列表,它会解决问题

步骤1:

 result=YOUR_MODELE_NAME.objects.values('PROP1','PROP2').all();

第2步:

 result=list(result)  #after getting data from model convert result to list

第三步:

 return HttpResponse(json.dumps(result), content_type = "application/json")

这似乎仍然会序列化为 json 数组(对象)而不是裸对象,这是 OP 所要求的。 iow,这与常规的序列化方法没有什么不同。
这将失败并出现 JSON 序列化错误。 Queryset 对象不可序列化
C
Community

使用 python 格式的 Django Serializer,

from django.core import serializers

qs = SomeModel.objects.all()
serialized_obj = serializers.serialize('python', qs)

json和python格式有什么区别?

json 格式将返回结果为 strpython 将以 listOrderedDict 形式返回结果


太不幸了
我得到 OrderedDict,而不是 dict
Z
Zags

要序列化和反序列化,请使用以下命令:

from django.core import serializers

serial = serializers.serialize("json", [obj])
...
# .next() pulls the first object out of the generator
# .object retrieves django object the object from the DeserializedObject
obj = next(serializers.deserialize("json", serial)).object

我得到'生成器对象没有属性'next'。任何想法?
@user2880391 我已经为 Python 3 更新了这个。这能解决吗?
J
Jack M.

您似乎无法序列化实例,您必须序列化一个对象的 QuerySet。

from django.core import serializers
from models import *

def getUser(request):
    return HttpResponse(json(Users.objects.filter(id=88)))

我用完了 django 的 svn 版本,所以这可能不在早期版本中。


如果这个框架不能做最基本的事情,用最常用的格式序列化一个该死的模型,那还有什么意义。
佚名
ville = UneVille.objects.get(nom='lihlihlihlih')
....
blablablab
.......

return HttpResponse(simplejson.dumps(ville.__dict__))

我返回我的实例的字典

所以它返回类似 {'field1':value,"field2":value,....}


这将打破:TypeError: <django.db.models.base.ModelState object at 0x7f2b3bf62310> is not JSON serializable
R
Reorx

这种方式怎么样:

def ins2dic(obj):
    SubDic = obj.__dict__
    del SubDic['id']
    del SubDic['_state']
return SubDic

或排除任何你不想要的东西。


i
iantbutler

与我对框架的期望相比,所有这些答案都有些笨拙,这是迄今为止我认为最简单的方法,如果您使用的是其余框架:

rep = YourSerializerClass().to_representation(your_instance)
json.dumps(rep)

这直接使用序列化器,尊重您在其上定义的字段,以及任何关联等。


E
Ehsan Ahmadi

这是一个项目,它可以序列化(现在基于 JSON)模型中的所有数据并自动将它们放入特定目录,然后它可以随时反序列化它......我已经用这个脚本亲自序列化了数千条记录,然后将它们全部加载回另一个数据库,而不会丢失任何数据。

任何对开源项目感兴趣的人都可以贡献这个项目并为其添加更多功能。

serializer_deserializer_model