将 django 升级到 1.6.5 后,django 对象不是 JSON 可序列化错误

Posted

技术标签:

【中文标题】将 django 升级到 1.6.5 后,django 对象不是 JSON 可序列化错误【英文标题】:django object is not JSON serializable error after upgrading django to 1.6.5 【发布时间】:2014-08-05 10:25:33 【问题描述】:

我有一个 django 应用程序,它在 1.4.2 版本上运行并且运行良好,但最近我将其更新为 django 1.6.5 并遇到如下一些奇怪的错误

实际上,我在我的网站功能中的用户/客户端注册过程中得到了这个

Request URL:    http://example.com/client/registration/
Django Version:     1.6.5
Exception Type:     TypeError
Exception Value:    <Client: test one> is not JSON serializable
Exception Location:     /usr/lib/python2.7/json/encoder.py in default, line 184
Python Executable:  /home/user/.virtualenvs/test_proj/bin/python
Python Version:     2.7.5

追溯

Traceback:
File "/home/user/.virtualenvs/test_proj/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  199.                 response = middleware_method(request, response)
File "/home/user/.virtualenvs/test_proj/local/lib/python2.7/site-packages/django/contrib/sessions/middleware.py" in process_response
  38.                     request.session.save()
File "/home/user/.virtualenvs/test_proj/local/lib/python2.7/site-packages/django/contrib/sessions/backends/db.py" in save
  57.             session_data=self.encode(self._get_session(no_load=must_create)),
File "/home/user/.virtualenvs/test_proj/local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py" in encode
  87.         serialized = self.serializer().dumps(session_dict)
File "/home/user/.virtualenvs/test_proj/local/lib/python2.7/site-packages/django/core/signing.py" in dumps
  88.         return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/usr/lib/python2.7/json/__init__.py" in dumps
  250.         sort_keys=sort_keys, **kw).encode(obj)
File "/usr/lib/python2.7/json/encoder.py" in encode
  207.         chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/json/encoder.py" in iterencode
  270.         return _iterencode(o, 0)
File "/usr/lib/python2.7/json/encoder.py" in default
  184.         raise TypeError(repr(o) + " is not JSON serializable")

Exception Type: TypeError at /client/registration/
Exception Value: <Client: test one> is not JSON serializable

我很困惑为什么更新后会出现上述 json 错误,顺便说一下,我在一些模型中使用了自定义的 json 字段,如下所示

proj/utils.py

from django.db import models
from django.utils import simplejson as json
from django.core.serializers.json import DjangoJSONEncoder


class JSONField(models.TextField):
    '''JSONField is a generic textfield that neatly serializes/unserializes
    JSON objects seamlessly'''

    # Used so to_python() is called
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        '''Convert our string value to JSON after we load it from the DB'''
        if value == '':
            return None
        try:
            if isinstance(value, basestring):
                return json.loads(value)
        except ValueError:
            pass
        return value

    def get_db_prep_save(self, value, connection=None):
        '''Convert our JSON object to a string before we save'''
        if not value or value == '':
            return None
        if isinstance(value, (dict, list)):
            value = json.dumps(value, mimetype="application/json")
        return super(JSONField, self).get_db_prep_save(value, connection=connection)

from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^proj\.util\.jsonfield\.JSONField"])

settings.py

SERIALIZATION_MODULES = 
     'custom_json': 'proj.util.json_serializer',
        

json_serializer.py

from django.core.serializers.json import Serializer as JSONSerializer
from django.utils.encoding import is_protected_type

# JSONFields that are normally incorrectly serialized as strings
json_fields = ['field_1', 'field_2']


class Serializer(JSONSerializer):
    """
    A fix on JSONSerializer in order to prevent stringifying JSONField data.
    """
    def handle_field(self, obj, field):
        value = field._get_val_from_obj(obj)
        # Protected types (i.e., primitives like None, numbers, dates,
        # and Decimals) are passed through as is. All other values are
        # converted to string first.
        if is_protected_type(value) or field.name in json_fields:
            self._current[field.name] = value
        else:
            self._current[field.name] = field.value_to_string(obj)

那么如何解决上述错误呢?有人可以解释一下导致错误的原因吗?

【问题讨论】:

【参考方案1】:

Django 1.6 将序列化程序从 pickle 更改为 json。 pickle 可以序列化 json 不能序列化的东西。

您可以在 settings.py 中更改 SESSION_SERIALIZER 的值,以从 Django 1.6 版本之前恢复行为。

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

您可能想阅读文档中有关 session serialization 的信息。

【讨论】:

是的,在 settings.py 中设置这一行已经解决了问题SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'。谢谢 什么样的东西在 JSON 中比在 Pickle 中不可序列化?谢谢 @aRkadeFR:对我来说,这是一个复杂的数据结构,有很多自己的类。 @Matthias 好的,谢谢。我选择回到 Pickle,因为对于我正在开发的当前网站来说,安全性并不是一个大问题。 @aRkadeFR:我在升级后遇到了日期时间对象的问题。【参考方案2】:

将此行设置为settings.py 将在升级到django 1.6 版本时清除错误

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

【讨论】:

【参考方案3】:

分析回溯后,JSONEncoder 似乎无法序列化您的 Client 模型的实例。通常,如果您尝试使用 jsonsimplejson 库序列化与其他模型(Many2ManyField 等)相关的模型,则会出现此类错误。

看这个https://docs.djangoproject.com/en/dev/topics/serialization/,你也可以根据需要使用一些3rd-party包如DjangoRestFramework

【讨论】:

以上是关于将 django 升级到 1.6.5 后,django 对象不是 JSON 可序列化错误的主要内容,如果未能解决你的问题,请参考以下文章

切换到django 3并返回django 2后无法登录Django项目

将 django 站点从 http 升级到 https 后,我不断收到“无效的 HTTP_HOST 标头”错误电子邮件

Django模板语言相关内容 Djan

django admin 静态文件在升级到 1.4 后停止工作

升级到 Django1.7 后,related_names 抛出错误

如何将多租户 django 应用程序部署到 AWS?