DjangoRestFramework ModelSerializer DateTimeField仅在对象创建时转换为当前时区

DjangoRestFramework ModelSerializer DateTimeField仅在对象创建时转换为当前时区,django,datetime,serialization,django-rest-framework,Django,Datetime,Serialization,Django Rest Framework,更新:这种行为被认为是一个bug,并在django rest framework 3.7中得到解决。序列化程序现在将根据服务器的时区一致地显示时间: 我有一个Django项目,我希望用户在某个时区。我有时区='Asia/Kolkata'和在我的设置中使用

更新:这种行为被认为是一个bug,并在django rest framework 3.7中得到解决。序列化程序现在将根据服务器的时区一致地显示时间:

我有一个Django项目,我希望用户在某个时区。我有
时区='Asia/Kolkata'
在我的设置中使用

我有一个包含datetimefield的模型。当我第一次创建对象时,modelserializer会给出datetimes,后面有一个
+5:30
。令人烦恼的是,带有
auto\u now\u add=True的datetimes给UTC datetimes一个尾随
Z
。我修复了这个问题,将字段的默认值设置为当前时间可调用

如果我在任何时候再次序列化该对象,则所有日期时间都以UTC为单位,并带有尾随的
Z
。从Django文档中,我希望序列化程序使用当前时区,默认为由
TIME\u ZONE='Asia/Kolkata'
设置的默认时区。我已经用
get\u current\u timezone\u name()
检查了视图中的当前时区,它是
'Asia/Kolkata'
。在我看来,我甚至尝试过使用
activate('Asia/Kolkata')
,但时间仍然以UTC返回


请注意,所有时间都是正确的(UTC时间早于5:30小时),我只是希望时间能够转换。所有日期时间都按预期的UTC时间存储在数据库中。

请查看以下文档:

签名:DateTimeField(格式=无,输入格式=无)

格式-表示输出格式的字符串。如果未指定,则默认为与DATETIME_格式设置键相同的值,除非设置为“iso-8601”。设置为格式字符串表示to_表示返回值应强制为字符串输出。格式字符串如下所述。将此值设置为“无”表示Python datetime对象应通过to_表示返回。在这种情况下,日期时间编码将由渲染器确定

当值None用于格式时,datetime对象将由to_表示返回,最终输出表示将由renderer类确定

对于JSON,这意味着默认的日期时间表示使用ECMA262日期时间字符串规范。这是ISO 8601的子集,使用毫秒精度,并包含UTC时区的“Z”后缀,例如:2013-01-29T12:34:56.123Z

因此,获取datetime对象的UTC(Z)表示形式实际上是默认行为

当您通过Djangorest创建更新模型实例时,将使用
数据
kwarg调用序列化程序,如果使用列表或详细视图,则不会发生这种情况

在这两种情况下,视图都将返回
serializer.data
。如果是创建/更新操作,这将是
序列化程序.已验证的\u数据
的表示,而如果是列表/详细信息操作,它将是实例的直接表示

在这两种情况下,表示都是通过调用
字段来实现的。使用默认的kwarg
格式=无
,将使字段返回普通字符串值

奇迹发生了:

  • 创建/更新:验证返回一个时区感知对象,其中包括您的标准时区。通过调用其
    isoformat()
    方法将其转换为字符串,并按原样返回
  • 列出/检索:django ORM将时间戳存储为UTC。通过调用其
    isoformat()
    方法将其转换为字符串,但DRF将
    +00:00
    替换为
    Z
    (请参见上面的链接)
因此,要使用时区偏移量获得所需的输出,可以将
format=None
或自定义strftime字符串传递到序列化程序中的datetime字段。但是,您将始终使用
+00:00
获得UTC时间,因为数据(幸运的是)存储为UTC时间

如果您希望实际偏移量为
'Asia/Kolkata'
,您可能需要定义自己的
日期时间字段

from django.utils import timezone
class CustomDateTimeField(serializers.DateTimeField):
    def to_representation(self, value):
        tz = timezone.get_default_timezone()
        # timezone.localtime() defaults to the current tz, you only
        # need the `tz` arg if the current tz != default tz
        value = timezone.localtime(value, timezone=tz)
        # py3 notation below, for py2 do:
        # return super(CustomDateTimeField, self).to_representation(value)
        return super().to_representation(value) 

这并不能解释为什么我在创建对象后立即得到不同的结果。另外,在“当前时区是用于呈现的时区”中,我假设这会覆盖JSON的“默认日期时间表示”,或者在从DB检索后本地化日期时间。最后,Django文档还明确指定:“当序列化aware datetime时,包括UTC偏移量,如下所示:“2011-09-01T13:20:30+03:00”。我想我已经解决了,有趣的问题。嗯。从Django文档来看,如果这是预期的行为,我会感到惊讶,尽管这似乎是Django本身的问题,而不是Djangorest框架的问题。我将研究您的修复。我认为这是非常理想的行为,请看第一句at对象在内部存储为UTC,并仅在模板和表单中呈现为用户的时区(“当前时区”)。这并不是说它们不会转换为序列化器。你的报价中的“唯一”对我来说没有出现。行为会像这样改变,这似乎是不必要的困惑。当然,它至少应该被记录在案。我更喜欢总是使用UTC或总是使用当前时区的行为。