Django RuntimeWarning:DateTimeField 收到 naive datetime

USE_TZ 开启时 last_login 等字段收到无时区 datetime 会报警;对齐系统时区与 settings.TIME_ZONE,并改用 timezone.now()。

Django 开着时区支持时,控制台突然冒出一条 RuntimeWarning,原文大致是:

/usr/local/lib/python2.7/dist-packages/django/db/models/fields/__init__.py:1453: RuntimeWarning: DateTimeField UserProfile.last_login received a naive datetime (2016-03-09 08:56:06.585692) while time zone support is active.

翻译一下:UserProfile.last_login 这个 DateTimeField 收到了一个不带时区信息的 naive datetime,而项目已经启用了时区支持(USE_TZ = True)。

原因

Django 在 USE_TZ = True 时希望写入数据库的是 aware datetime(带 tzinfo)。若代码里用了 datetime.now()、或某处把系统本地时间当「无时区对象」塞进字段,就会触发这条警告。系统时区与 settings.py 里 TIME_ZONE 不一致时,也更容易搅在一起,登录时间、定时任务看起来「偏了几个小时」。

我当时的处理

两边对齐:

  1. 系统时区:把服务器时区调到你真实业务所在区(或统一用 UTC)。
  2. Django `settings.py`:TIME_ZONE、USE_TZ 与部署约定一致。

从根上更稳妥的写法是:业务代码里用 django.utils.timezone.now(),避免 datetime.datetime.now() 产生 naive 对象。当年这条备忘重点是「先把系统和 Django 时区设对」,警告就会消停很多。

为何记下

一人公司的后台、用户系统经常自己维护。时区问题不致命,但会污染日志、干扰「最后登录时间」这类字段。看到 received a naive datetime while time zone support is active,优先查 系统时区 + TIME_ZONE + 是否误用 naive now(),比先怀疑数据库类型更快。

No comments yet