Loaddata没有正确处理时间戳和时区

时间:2012-09-17 15:38:24

标签: python django yaml

我正在使用启用了mysql和timezones的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导出的相同格式
  3. 有什么方法可以告诉django这是一个UTC日期吗?

4 个答案:

答案 0 :(得分:21)

问题源于PyYAML。当loaddata将日期时间移交给PyYAML时,它需要知道日期时间,将时间调整为UTC,然后返回一个天真的日期时间,从而生成警告。

有一个Django ticket,以及有关该问题的PyYAML ticket。两者都涉及上述意外行为的更多细节。从门票中的评论来看,这个问题似乎不太可能很快得到解决。

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

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

希望有所帮助。

答案 1 :(得分:8)

来自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'

......会奏效。

答案 2 :(得分:1)

您可以将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'}

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

答案 3 :(得分:0)

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

即,手动更改YAML固定装置,使其:

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

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