编辑:这已经被认为是一个错误,它看起来像一个修复正在进行中:https://github.com/tomchristie/django-rest-framework/issues/3732#issuecomment-267635612
我有一个Django项目,我希望用户在某个时区.我TIME_ZONE = 'Asia/Kolkata'
和USE_TZ = True
我的设置.
我有一个包含datetimefield的模型.当我第一次创建对象时,modelserializer给出带尾随的日期时间+5:30
.令人讨厌的是,日期时间auto_now_add=True
为UTC日期时间提供尾随Z
.我通过使字段的默认值为当前时间的可调用来修复此问题.
如果我在任何时候再次序列化对象,则所有日期时间都是UTC,并带有尾随Z
.从Django文档中,我希望序列化程序使用当前时区,默认为默认时区设置TIME_ZONE = 'Asia/Kolkata'
.我已经在我的视图中检查了当前时区get_current_timezone_name()
,它是'Asia/Kolkata'
.我甚至尝试过activate('Asia/Kolkata')
在我的视图中使用,但时间仍在UTC中返回.
请注意,所有时间都是正确的(UTC时间早于5:30),这正是我期望转换的时间.所有日期时间都按照预期的UTC时间存储在数据库中.
我错过了什么,或者这是Django Rest Framework序列化程序的错误?
看看这里的文档:http://www.django-rest-framework.org/api-guide/fields/#datetimefield
签名:DateTimeField(format = None,input_formats = None)
format - 表示输出格式的字符串.如果未指定,则默认为与DATETIME_FORMAT设置键相同的值,除非设置,否则将为"iso-8601".设置为格式字符串表示to_representation返回值应强制转换为字符串输出.格式字符串如下所述.将此值设置为None表示to_representation应返回Python datetime对象.在这种情况下,日期时间编码将由渲染器确定.
如果将值设置为None,则datetime对象将由to_representation返回,最终输出表示将由renderer类确定.
对于JSON,这意味着默认的日期时间表示使用ECMA 262日期时间字符串规范.这是ISO 8601的子集,使用毫秒精度,并包括UTC时区的"Z"后缀,例如:2013-01-29T12:34:56.123Z.
因此,获取datetime对象的UTC(Z)表示实际上是默认行为.
当您通过Djangorest 创建或更新模型实例时,将使用data
kwarg 调用序列化程序,如果您使用列表或详细信息视图,则不会发生这种情况.
在这两种情况下,您的视图都将返回serializer.data
.在创建/更新操作的情况下,这将是表示serializer.validated_data
,而在列表/细节操作的情况下,它将是实例的直接表示.
在这两种情况下,通过field.to_representation
使用默认的kwarg 调用来实现表示format=None
,这将使字段返回纯字符串值.
魔术发生在这里:
create/update:验证返回一个时区感知对象,其中包括您的标准时区.它通过调用其isoformat()
方法转换为字符串,并按原样返回.
list/retrieve:django ORM将时间戳存储为UTC.它通过调用isoformat()
方法转换为字符串,但DRF替换+00:00
为Z
(参见上面的链接).
因此,要获得具有时区偏移量的所需输出,您可以将format=None
自定义strftime字符串传递给序列化程序中的DateTimeField.但是,您将始终获得UTC时间+00:00
,因为这是(幸运的是)存储的数据.
如果你想要实际的偏移量'Asia/Kolkata'
,你可能需要定义自己的DateTimeField
:
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)