22

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

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

为了测试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”字段中获取包含用户本地时区中的日期时间,这些字段通过UnicodeJSONRenderer到 aModelSerializer然后保存到数据库。但是,它们会像在 UTC中一样保存。

在这一点上,我希望序列化程序(或解析器)将用户输入的日期时间视为需要从“亚洲/耶路撒冷”转换为 UTC 的日期时间,然后再保存到数据库,因为我执行了timezone.activate(pytz.timezone("Asia/Jerusalem")).

当数据通过JSONParser.
虽然期望返回的 JSON 中的 DateTime 字段位于中间件中激活的时区中,但它们以 UTC 的形式返回。

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

4

3 回答 3

35

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

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',
        )
于 2013-09-03T23:10:30.583 回答
16

@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')
于 2015-06-01T09:57:57.637 回答
4

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

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

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

  1. USE_TZ必须为真
  2. 设置TIME_ZONE为指定默认时区
  3. 设置REST_FRAMEWORK.DATETIME_FORMAT为适合您的前端代码的格式。
于 2018-10-16T09:28:10.597 回答