Django-rest-framework时区感知渲染器/解析器

时间:2013-06-26 22:30:42

标签: django django-rest-framework

我正在构建一个应用程序,可以为位于世界各地的人们提供服务 我正在使用Django-Rest-Framwork进行客户端和服务器之间的通信 所有DateTime值都以UTC格式保存到数据库中(我在settings.py中有USE_TZ = TrueTIME_ZONE = 'Greenwich'

我将从用户那里获得他/她的当地时区。

测试 DRF的时区感知我用固定的时区编写了这个中间件:

import pytz
from django.utils import timezone

class TimezoneMiddleware(object):
    def process_request(self, request):
        timezone.activate(pytz.timezone("Asia/Jerusalem"))

问题是:
我有一个案例,我从用户的“start_time”和“end_time”字段中获取用户的 LOCAL 时区中的日期时间,该时区通过UnicodeJSONRenderer到{{1}然后保存到DB。但是,它们保存为,就好像它们是UTC 一样。

此时我希望序列化程序(或解析器)将用户的日期时间输入视为日期时间,需要从“亚洲/耶路撒冷”转换为UTC,然后保存到数据库,因为我执行了{{1} }。

通过ModelSerializer在响应中解析数据时也是如此 虽然期望返回的JSON中的DateTime字段位于中间件中激活的时区中,但它们将以UTC格式返回。

如何在DRF中轻松实现这一目标?

3 个答案:

答案 0 :(得分:34)

我遇到了同样的问题并通过添加新类型的字段来解决它:

class DateTimeTzAwareField(serializers.DateTimeField):

    def to_native(self, value):
        value = timezone.localtime(value)
        return super(DateTimeTzAwareField, self).to_native(value)

现在您可以在ModelSerializer中使用它:

class XSerializer(serializers.ModelSerializer):
    start = DateTimeTzAwareField()
    end = DateTimeTzAwareField()

    class Meta:
        model = XModel
        fields = (
             'id',
             'start',
             'end',
        )

答案 1 :(得分:17)

@yakxxx的答案似乎是最好的解决方案。 我在更新后再次发布它以使用更新版本的restframework

在我的目录中(common / serializers.py)

from rest_framework import serializers
from django.utils import timezone

class DateTimeFieldWihTZ(serializers.DateTimeField):

    def to_representation(self, value):
        value = timezone.localtime(value)
        return super(DateTimeFieldWihTZ, self).to_representation(value)

在我的应用程序中

from common.serializers import DateTimeFieldWihTZ

class MyObjectSerializer(serializers.ModelSerializer):

    start = DateTimeFieldWihTZ(format='%d %b %Y %I:%M %p')
    end = DateTimeFieldWihTZ(format='%d %b %Y %I:%M %p')

答案 2 :(得分:3)

自Django REST Framework v3.8.0(2018年5月发布)以来,您不再需要自定义DateTimeField。

在以前的版本中,Django REST Framework在解析日期(DateTimeField.to_internal_value())时仅将本机日期时间转换为时区感知日期时间,而在呈现数据时间字段(DateTimeField.to_representation())时不进行转换。 This在DRF v3.8.0中已修复。

您可能需要更改以下设置:

  1. USE_TZ必须为True
  2. 设置TIME_ZONE以指定默认时区
  3. REST_FRAMEWORK.DATETIME_FORMAT设置为适合您的前端代码的格式。