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


157

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


看起来您可以序列化一个1对象的查询集,但是您不能使用from的类django.core来执行此操作。是否有不使用序列化查询集的特定原因?
Jack M.

1
queryset序列化程序将结果包装在比必须多的两层中。因此,您必须执行data [0] .fields.name而不是data.name。
杰森·克里斯塔

我也这么想。当我为django后端编写GWT接口时遇到了同样的问题。看起来大卫可能正在某事上。
Jack M.

Answers:


241

您可以轻松地使用列表来包装所需的对象,而这正是Django序列化程序正确地序列化它所需要的,例如:

from django.core import serializers

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

9
但是作为响应,您需要索引JSON对象的零元素才能到达序列化的对象。只是要注意。
达沃·卢西奇

10
以及如何将所有引用的对象与根对象一起序列化?
paweloque 2011年

1
您是否不[0]想像@DavorLucic建议的那样在最后一行的结尾?而且,您不需要在列表文字中使用逗号结尾(因为对PEP8的热爱;)。
滚刀2014年

反序列化还需要额外的步骤;参见stackoverflow.com/a/29550004/2800876
Zags

4
这对我不起作用。Django抛出AttributeError'tuple'对象没有属性'_meta'–
adamF

71

如果您要处理的模型实例列表是您最好的选择serializers.serialize(),那么它会完全满足您的需求。

但是,您要尝试序列化单个对象而不是对象的对象时会遇到问题list。这样,为了摆脱各种黑客攻击,只需使用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)

而已!:)


6
这种失败UUID领域,应当否则清除
阿尔文

2
datetime字段失败。json.loads(serialize('json', [obj]))[0]序列化器django.core.serializers.serialize
为时以

43

为了避免数组包装,请在返回响应之前将其删除:

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,它看起来像是完成这项工作的理想工具。


9
如果这是在Django中序列化单个模型的最佳方法,那将是可怕的,因为您无需反序列化json并序列化回去。
赫伯特

@赫伯特,也许。但是有。如果您有更好的方法,我会全力以赴。这不应该有太多实际的缺点,因为获取和解码单个对象不应该占用大量资源。如果要隐藏恐怖,则使其成为辅助函数或与对象扩展/混合作为一种新方法。
朱利安

1
隐藏恐怖不是问题,甚至不是解决方案。令我惊讶的是,这是django最好的方法。
赫伯特

14

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

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

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)
``

3
该解决方案简单而优雅。编码器可与json.dumpsjson.dump方法一起使用。这样,您无需更改应用程序的工作流程,因为您可以使用自定义对象或在转换为json之前添加另一个方法调用。只需将您的转换代码添加到编码器中,即可开始使用。
Claudiu

11

听起来您要问的是涉及序列化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中存在魔术)
Skylar

8

如果您要问如何从模型中序列化一个对象,并且知道仅要在查询集中获取一个对象(例如,使用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]”?
朱利安

5

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

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 是模型字段的有序列表,可以从实例和模型本身进行访问。


3
尽管乍一看这个主意似乎不错,但应该指出使用这种方法会产生后果。您将一个特定的序列化输出绑定到模型。
乔纳斯·吉雷加特

@JonasGeiregat,因为此方法是基于模型定义的,所以该方法有什么问题?可悲的是,这似乎是返回同时包含字段和实例主键的json对象的唯一方法。
dopatraman,

5

这是我的解决方案,可让您轻松自定义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()
T.Coutlakis 2015年

4

使用清单,将解决问题

第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所要求的。现在,这与常规序列化方法没有什么不同。
朱利安

1
这将失败,并显示JSON序列化错误。Queryset对象不可序列化
dopatraman,

4

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

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

我得到“发电机对象没有属性”下一个。任何想法?
user2880391

1
@ user2880391我已经为Python 3更新了它。
Zags

4

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

.values()文档:https ://docs.djangoproject.com/zh/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",
}

3

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

2

使用Django序列化器python格式,

from django.core import serializers

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

jsonpython格式有什么区别?

json格式将返回的结果str,而python将在返回的结果要么listOrderedDict


太不幸了
JPG

我得到了OrderedDict,不是dict
user66081 '19

1

似乎您不能序列化一个实例,而必须序列化一个对象的QuerySet。

from django.core import serializers
from models import *

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

我用完了svndjango发行版,因此在较早的版本中可能不存在。


1
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
朱利奥·马林斯

1

这样呢:

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

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


0

与我希望从框架(最简单的方法)相比,所有这些答案都有些棘手,如果您使用其余框架,我认为到目前为止,这是最简单的方法:

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

这将直接使用Serializer,同时尊重您在其上定义的字段以及任何关联等。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.