【问题标题】:How to return DateTime in different timezone from Django Rest Framework serializer如何从 Django Rest Framework 序列化程序返回不同时区的 DateTime
【发布时间】:2019-05-13 22:52:19
【问题描述】:

在 Django Rest Framework 中使用任意时区返回某些 Django 模型的DateTimeField 的 Python 方式是什么?

目前我的视图以 UTC 格式返回 DateTime,因为据我所知,Django 将时区感知的日期时间存储为 UTC 时区中的日期时间。

型号:

class TimezoneMixin(models.Model):
    TIMEZONES = [(i, i) for i in country_timezones['ru']]

    timezone = models.CharField(choices=TIMEZONES, ...)

    class Meta:
        abstract = True

    def get_timezone(self):
        if self.timezone:
            return timezone(self.timezone)
        return get_current_timezone()


class Organization(TimezoneMixin, models.Model):
    ...

class Event(models.Model):
    organization = models.ForeignKey(Organization, ...)
    date_created = models.DateTimeField(auto_now_add=True, ...)
    ...

序列化器:

class EventSerializer(serializers.ModelSerializer):

    class Meta:
        model = Event
        fields = ('organization', 'date_created', ...)

在 ViewSet 中,我按如下方式填充数据

organization_id = ...  # Some logic to get required organization_id

data = {
    'date_created': timezone.now(), # django.utils.timezone
    'organization': organization_id,
    ...
}

serializer = EventSerializer(data=data)
if serializer.is_valid():
    serializer.save()
    response_data = serializer.data.copy()
    # Some logic to rename one of the keys in response data
    ...
    return Response(response_data, ...)  # rest_framework.response.Response

即使我将 timezone.now() 替换为 timezone.now().astimezone(organization.get_timezone()) 之类的东西,我仍然会收到 UTC DateTime 作为响应。

我是否正确,从 response_data 解析 date_created 字符串,从中创建一个 DateTime 对象,转换为不同的时区并在视图末尾再次格式化为字符串不是一个好主意?还有哪些方法?

【问题讨论】:

  • 最明智的方法是在任何地方都使用时区感知或 UTC,并且只在显示时转换为本地时区。
  • 日期时间可以同时是时区感知和 UTC 我错了吗?
  • 他们可以(timezone.now() 是)。然后他们知道是 UTC。
  • 理想情况下,API 应该是 UTC。显示时间是呈现给最终用户的时间。例如,在 JS 代码中,您可以在浏览器中查询用户的时区并相应地显示。 — 在 API 中包含当地时间只会让开发人员混淆它实际上是哪个时区(它取决于服务器位置吗?它是 UTC 吗?它是否取决于某些用户设置?它是否尝试使用 geoip 检测客户端时区?什么?如果我通过代理?)
  • 感谢您的建议。作为用户,我也更愿意使用基于 UTC 的 API。但是,由于 API 客户端的当前限制,我需要在不同的时区发送响应。

标签: python django datetime django-rest-framework timezone


【解决方案1】:

您需要localtime() 来获取当前时区的时间,因为无论TIME_ZONE 的值如何,now() 将始终返回 UTC 时间。

您可以将任意时区传递给本地时间:

localtime(timezone='SOMETHING')

【讨论】:

  • 听起来就像我需要的一样。你能建议它所属的地方吗?我试图把这个逻辑放到我自定义的序列化器的serializer.data-like 属性中。但是在自定义属性的情况下,日期时间不会像香草serializer.data 那样自动转换(序列化?)为字符串。还不知道为什么。
【解决方案2】:

我能够在不解析日期时间字符串的情况下获得任意时区的时间戳,因为serializer 提供了对已保存instance 的访问。所以下面是我的解决方案

response_data = serializer.data.copy()
# Some logic to rename one of the keys in response data
...
event_date_created_utc = serializer.instance.date_created
# Basically calls get_timezone on Organization instance and returns the result
organization_timezone = get_timezone_by_organization_id(organization_id)
response_data['date_created'] = timezone.localtime(event_date_created_utc,
                                                   timezone=organization_timezone).isoformat()
return Response(response_data, ...)  # rest_framework.response.Response

感谢 Edgar R. Mondragón 提到 localtime() 及其用法。

【讨论】:

    【解决方案3】:

    序列化程序使用您在 settings.py 文件中设置的默认 TIME_ZONE

    如果你想为一个字段设置 TIMEZONE。

    import pytz
    class WeatherReportSerializer(serializers.ModelSerializer):
        DatetimeValue = serializers.DateTimeField(default_timezone=pytz.timezone('Asia/Kolkata'))
        
        class Meta:
            model = ...
            fields = [..., ..., ...]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-19
      • 2019-11-20
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2019-05-25
      • 2020-10-13
      相关资源
      最近更新 更多