【问题标题】:Django Sessions, handling of datetime typesDjango Sessions,处理日期时间类型
【发布时间】:2023-04-09 04:55:01
【问题描述】:

我在当前的 django 项目中使用会话,最近收到 'Object of type 'date' is not JSON serializable' 错误 - 由于下面的 move_in_date 字段。

将以下模型的模型形式保存到会话时:

if form.is_valid():
        request.session.update(form.cleaned_data)

我的模特:

class Address(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    house_name_number = models.CharField(max_length=255, verbose_name="house name or number")
    street_name = models.CharField(max_length=255)
    town_city = models.CharField(max_length=255)
    county = models.CharField(max_length=255)
    postcode = models.CharField(max_length=8)

    same_address = models.BooleanField() 
    move_in_date = models.DateField(null=True, blank=True)

我已尝试按照文档的建议使用 DjangoJSONEncoder 来解决该问题,它可以通过 SESSION_SERIALIZER=DjangoJSONEncoder 的设置处理日期时间(这应该是序列化程序而不是编码器吗?),但尝试这样做或SESSION_SERIALIZER=PickleSerializer 都给出一个属性错误 - ... 没有属性 'rsplit'

此外,我使用 django 向导在会话中存储中间数据(例如导致上述日期问题的字段)。我现在已经将应用程序的那部分切换为使用单独的视图以获得灵活性(因为注册不仅仅是一个线性路径),django 向导没有这个问题,它是如何解决这个问题的?

使用堆栈跟踪更新

Traceback (most recent call last):
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/deprecation.py", line 142, in __call__
    response = self.process_response(request, response)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/middleware.py", line 58, in process_response
    request.session.save()
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 83, in save
    obj = self.create_model_instance(data)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 69, in create_model_instance
    session_data=self.encode(data),
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py", line 98, in encode
    serialized = self.serializer().dumps(session_dict)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/signing.py", line 93, in dumps
    return json.dumps(obj, separators=(',', ':')).encode('latin-1')
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'date' is not JSON serializable

尝试 DjangoJSONEncoder 的堆栈跟踪:

Traceback (most recent call last):
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/deprecation.py", line 138, in __call__
    response = self.process_request(request)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/middleware.py", line 20, in process_request
    request.session = self.SessionStore(session_key)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/db.py", line 18, in __init__
    super(SessionStore, self).__init__(session_key)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/contrib/sessions/backends/base.py", line 51, in __init__
    self.serializer = import_string(settings.SESSION_SERIALIZER)
  File "/Users/Barclay/.virtualenvs/switcher5/lib/python3.6/site-packages/django/utils/module_loading.py", line 15, in import_string
    module_path, class_name = dotted_path.rsplit('.', 1)
AttributeError: type object 'DjangoJSONEncoder' has no attribute 'rsplit'

【问题讨论】:

  • 包括错误的完整错误回溯。什么序列化程序导致此错误?你也可以发一下吗?
  • 感谢更新了堆栈跟踪,认为它使用不支持日期时间对象的默认 JSONSerializer
  • 默认的 jsonserializer 不起作用。您必须为此创建自己的序列化程序。
  • 感谢文档提到可以使用 DjangoJSONEncoder 并且尝试 PickleSerializer 都会导致属性错误?

标签: django session


【解决方案1】:

一些困惑的事情正在打击你:

  1. 设置序列化程序时,不要提供类引用,而是提供虚线部分。这在错误中可以看到:

    module_path, class_name = dotted_pa​​th.rsplit('.', 1)

  2. DjangoJSONEncoder 不是序列化程序的正确解决方案。它在文档中被引用为一种在将模型放入会话之前序列化模型的方法。
  3. 如果你想制作一个智能序列化器,那么你仍然需要创建一个序列化器,它应该支持dumpsloads 接口,分别利用JsonEncoderJsonDecoder
  4. Pickle 序列化程序可以正常工作,但如前所述,您需要提供 dotted path

如果您想使用 JSON 作为序列化程序,那么这可能是一个好的开始:

from django.core.serializers.json import DjangoJSONEncoder
from django.core.signing import JSONSerializer as BaseJSONSerializer


class SmartJSONSerializer(BaseJSONSerializer):
    def dumps(self, obj):
        return json.dumps(obj, separators=(',', ':'), cls=DjangoJSONEncoder).encode('latin-1')

【讨论】:

  • 感谢 json.loads 使用的标准解码器也可以支持日期时间?
  • 否,但那是因为 JSON 没有日期时间类型。有关更多信息和可能的解决方案,请参阅 here
  • 谢谢,太完美了
猜你喜欢
  • 2013-06-30
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-06
相关资源
最近更新 更多