【问题标题】:TypeError: <object> is not JSON serializableTypeError: <object> 不是 JSON 可序列化的
【发布时间】:2016-08-02 00:32:58
【问题描述】:

我试图在 Django 中使用 json.dumps() 将对象编码为 json,但是当我传入 python 对象时,它会引发此错误。

TypeError: <OrgInvite: OrgInvite object> is not JSON serializable

我的假设是,即使 JSON 只能编码某些数据类型,其中一种数据类型是对象。我在 Stack Overflow 上阅读了另一个问题,解决此问题的一个好方法是使用 .__dict__ 从对象中创建一个字典,我尝试了这个,它说我的新字典中的一个键 _state 是不可序列化的。我不确定这个 _state 键是从哪里来的,并且想知道有没有办法将我的对象转换为没有额外字段的字典,以便我可以将其编码为 JSON?

型号:

class OrgInvite(models.Model):
    token = models.CharField(max_length=16, unique=True, null=False)
    account_id = models.ForeignKey(Account, on_delete=models.CASCADE, null=False)
    org_id = models.ForeignKey(Org, on_delete=models.CASCADE, null=False)
    used = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    name = models.CharField(max_length=70)
    email = models.CharField(max_length=255)

查看:

def get_invite(token):
    if not token:
        raise Exception("Invitation token is not specified")

    invitation = OrgInvite.objects.get(token=token)
    if not invitation:
        raise Exception("Invitation token is invalid.")

    return invitation

def invite_accept_redirect(token):
    # """ -Redirects to the accept invite frontend view with pre-fetched data. """

    try:
        invite = get_invite(token)
        if not invite:
            raise Exception("Invitation token is invalid")
        if invite.used:
            invite = {'used': True}
    except:
        invite = {'invalid': True}
        raise Exception("Resource not found.")

    base = "home/accept"

    url = '{}/{}?data={}'.format(base, token, urllib.quote_plus(json.dumps(invite.__dict__)))

    return redirect(url)

控制台:

>>> oi = OrgInvite.objects.get(token=100) 
>>> oi
<OrgInvite: OrgInvite object>
>>> oix = oi.__dict__
>>> oix
{'used': False, 'name': u'', '_state': <django.db.models.base.ModelState object at 0x10377a610>, 'email': u'', 'token': u'100', 'org_id_id': 101, 'account_id_id': 301, 'is_admin': False, 'id': 1}
>>> json.dumps(oix)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <django.db.models.base.ModelState object at 0x10377a610> is not JSON serializable

【问题讨论】:

  • namedtuple 类使用._asdict() 并将事物作为字典返回。为您的代码使用相同的接口可能很有价值。
  • @WayneWerner 你在说什么? Django 模型及其序列化与namedtuple 无关
  • 通过._asdict() 方法返回字典。我提到namedtuple 作为标准库中已经这样做的源。也许它不太适合 OP 的情况,但可以完成他们需要的(或其他有类似问题的人)。

标签: json django object python-2.x


【解决方案1】:

object 不是这些类型之一。字典、列表(可能是元组)、浮点数、字符串、整数、布尔值和 None 我相信是 Python 可以原生序列化为 JSON 的类型。

不过,看起来 Django has some built-in serializers 可能适合你。

我猜

from django.core import serializers
data = serializers.serialize("json", OrgInvite.objects.filter(token=100))

应该适合你

【讨论】:

  • 不,序列化程序需要一个查询集而不是模型实例。
  • 啊...所以它需要的不仅仅是一个结果。
  • 所以你可以通过OrgInvite.objects.filter(token=100) 获取查询集。
  • 这会将实例序列化到一个列表中,这是不正确的。
【解决方案2】:

如果您使用invite.__dict__,它将为您提供与一个invite 对象相关的所有数据的字典。但是,dict 的值不一定是原始类型,而是对象(ModelState 只是其中之一)。序列化不仅不会工作,因为 json 不接受 python 对象,而且您还可以序列化很多未使用的元数据。

查看json official website 以了解哪些数据类型是 json 可序列化的。修复方法是使用django model serializer,或者手动创建一个符合 json 格式的 dict。

【讨论】:

    【解决方案3】:

    __dict__ 给出了实例的所有属性,但您不想要所有额外的包袱——出于序列化的目的,您只对字段感兴趣。

    您的模型不包含任何特殊内容,因此内置辅助函数 model_to_dict 应该足以满足您的需求:

    import json
    from django.forms.models import model_to_dict
    
    oi = OrgInvite.objects.get(token=100) 
    oi_dict = model_to_dict(oi)
    oi_serialized = json.dumps(oi_dict)
    

    您的示例很简单,只包含CharFieldBooleanFieldForeignKey,所有这些我们都可以简单地转储到json

    对于更复杂的模型,您可以考虑编写自己的serializer。在这种情况下,我建议使用流行的django-rest-framework,它可以为您完成所有工作。

    from rest_framework import serializers
    
    class OrgInviteSerializer(serializers.ModelSerializer):
        class Meta:
            model = OrgInvite
            fields = '__all__'
    

    【讨论】:

    • 工作就像一个魅力!今后我会牢记这一点。
    猜你喜欢
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 2019-02-08
    • 2013-05-11
    • 2014-08-13
    相关资源
    最近更新 更多