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

Posted

技术标签:

【中文标题】如何在 Django 中序列化模型实例?【英文标题】:How do you serialize a model instance in Django? 【发布时间】:2010-10-19 21:53:40 【问题描述】:

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

【问题讨论】:

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

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

from django.core import serializers

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

【讨论】:

但作为响应,您需要索引 JSON 对象的零元素以获取序列化对象。只是需要注意的一点。 那么如何将所有引用的对象与根对象一起序列化? 你不想在最后一行的末尾[0],就像@DavorLucic 建议的那样吗?并且不需要在您的列表文字中使用尾随逗号(为了 PEP8 的爱;)。 反序列化还需要一个额外的步骤;见***.com/a/29550004/2800876 这对我不起作用。 Django 抛出 AttributeError 'tuple' object has no attribute '_meta'【参考方案2】:

如果您要处理模型实例列表,最好使用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【参考方案3】:

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

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 最好的方法。【参考方案4】:

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

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

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 的部分,或者你没有正确调用它。【参考方案5】:

听起来您的问题涉及序列化 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 中有魔法)【参考方案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]" ?【参考方案7】:

如果您想将 单个模型对象作为 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))

【讨论】:

【参考方案8】:

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

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

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

注意:我使用的是 Django Rest Framework

@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",

【讨论】:

【参考方案9】:

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

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 对象的唯一方法。【参考方案10】:

这是我的解决方案,它允许您轻松自定义 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()【参考方案11】:

使用列表,它会解决问题

第一步:

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

第二步:

 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 对象不可序列化【参考方案12】:

Django Serializerpython格式一起使用,

from django.core import serializers

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

jsonpython格式有什么区别?

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

的形式返回结果

【讨论】:

太不幸了 我得到的是OrderedDict,而不是dict【参考方案13】:

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

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 更新了这个。这能解决吗?【参考方案14】:

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

from django.core import serializers
from models import *

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

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

【讨论】:

如果这个框架不能做最基本的事情,用最常用的格式序列化一个该死的模型,那还有什么意义呢。【参考方案15】:
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 【参考方案16】:

这样怎么样:

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

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

【讨论】:

【参考方案17】:

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

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

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

【讨论】:

【参考方案18】:

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

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

serializer_deserializer_model

【讨论】:

以上是关于如何在 Django 中序列化模型实例?的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 中使用 natural_keys 时,如何区分创建和更新?

风格 - 何时序列化 Django 模型实例:信号与模型的保存方法

如何在 django 的一个序列化程序中拥有两个模型

如何运行保存在模型实例中的 Django 代码?

当嵌套序列化程序中有另一个模型(manytomany)时,如何在 django 模型上发布,我想同时创建两者

如何在Django Rest Framework中序列化三个具有多对多关系的模型