【问题标题】:Loaddata not dealing with timestamps and timezones properlyLoaddata 未正确处理时间戳和时区
【发布时间】:2012-09-09 20:50:41
【问题描述】:

我正在使用启用了 mysql 和时区的 django 1.4.1。我向 yaml 做了一个转储数据,修改了一些字段以创建一些测试数据,并试图将其加载回来。然而,即使指定了 tz,Django 仍然抱怨天真的日期时间

具体来说,我的 loaddata 有:

fields: {created_date: !!timestamp '2012-09-15 22:17:44+00:00', ...

但是 loaddata 给出了错误:

RuntimeWarning: DateTimeField received a naive datetime (2012-09-15 22:17:44) while time zone support is active.

这对我来说没有多大意义,因为它是:

  1. UTC 时间戳
  2. 与 Django 使用 dumpdata 导出的完全相同的格式

有什么方法可以告诉 django 这是一个 UTC 日期吗?

【问题讨论】:

    标签: python django yaml


    【解决方案1】:

    来自docs...

    在序列化感知日期时间时,包括 UTC 偏移量,例如 这个:

    "2011-09-01T13:20:30+03:00"
    

    对于一个天真的日期时间,显然不是:

    "2011-09-01T13:20:30"
    

    ...所以不是...

    created_date: !!timestamp '2012-09-15 22:17:44+00:00'
    

    ...任何一个...

    created_date: '2012-09-15T22:17:44+00:00'
    

    ...或...

    created_date: '2012-09-15T22:17:44Z'
    

    ...会起作用的。

    【讨论】:

    • 这个解决方案对我不起作用。从例如更改 YAML 夹具“2019-01-05 01:05:45.754264+00:00”仍为“2019-01-05T01:05:45.754264+00:00”或“2019-01-05T01:05:45+00:00”发出警告。
    【解决方案2】:

    问题源于 PyYAML。当 loaddata 将 datetime 交给 PyYAML 时,它会获取感知的 datetime,将时间调整为 UTC,然后返回一个 naive datetime,它会生成警告。

    有一个Django ticket 和一个PyYAML ticket 与此问题有关。两者都对上述意外行为进行了更详细的介绍。从门票中的cmets来看,这个问题似乎不太可能很快得到解决。

    您是否在项目的 settings.py 中设置了TIME_ZONE = 'UTC',您将在正确的时间加载,但您仍然会收到警告。如果您的时区设置为其他任何时间,Django 会将日期时间视为本地时间,并将其调整为 UTC,这可能是不希望的。

    避免这种情况的最佳方法是使用 JSON 作为序列化格式。

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      您可以将 django/core/serializers/pyyaml.py 复制到您的项目目录, 并替换下面的代码(在ver.1.9.9的情况下可能是78-79行)

      for obj in PythonDeserializer(yaml.load(stream, Loader=SafeLoader), **options):
          yield obj
      

      output = yaml.load(stream, Loader=SafeLoader)
      for a_model in output:
          for key, value in a_model.items():
              if key == 'fields':
                  for vkey, vvalue in value.items():
                      if isinstance(vvalue, datetime.datetime):
                          value[vkey] = vvalue.replace(tzinfo=pytz.utc)
      for obj in PythonDeserializer(output, **options):
          yield obj
      

      当然 pytz 已经安装并且

      import pytz
      

      需要。

      此代码会将所有原始日期时间值转换为 UTC 感知。

      要覆盖默认序列化程序,请在 settings.py 中添加 SERIALIZATION_MODULES:

      SERIALIZATION_MODULES = {'yaml': 'yourproj.pyyaml'}
      

      我希望这个猴子补丁能正常工作。

      【讨论】:

        【解决方案4】:

        我想继续使用 YAML 而不是 JSON 固定装置,这样我就可以在数据中包含 cmets。这里的解决方法为我解决了这个问题:https://code.djangoproject.com/ticket/18867

        即,手动更改 YAML 夹具,使其:

        • 不使用 !!timestamp YAML 标签
        • 用引号将时间戳值括起来
        • 在时间戳值中包含时区信息

        ...显然这会触发 Django 的时间戳解析逻辑,而不是损坏的 PyYAML 逻辑。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          相关资源
          最近更新 更多