Django 1.7 からマイグレーションシステムが組み込まれました. しかし, このマイグレーションシステムでモデルの DateTimeField にタイムゾーン付きのデフォルト値を設定すると ValueError 例外が送出されます.
問題発生の手順
以下のようなモデルを作成するとします. フィールドのデフォルト値にはそれぞれタイムゾーン付きの現在時刻が設定されています. django.utils.timezone.now は settings.USE_TZ = True の場合にタイムゾーン付きになります.
from datetime import datetime
from django.db import models
from django.utils.timezone import now, utc
class SampleModel(models.Model):
added = models.DateTimeField(default=datetime.utcnow().replace(tzinfo=utc))
updated = models.DateTimeField(default=now())
上のモデルについて makemigration を実行すると ValueError が送出されます.
$ python manage.py makemigrations
Migrations for 'app':
0001_initial.py:
- Create model SampleModel
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
〜〜〜 省略 〜〜〜
File "**********/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 271, in serialize
raise ValueError("Cannot serialize datetime values with timezones. Either use a callable value for default or remove the timezone.")
ValueError: Cannot serialize datetime values with timezones. Either use a callable value for default or remove the timezone.
問題の修正方法
問題の修正方法は ValueError 例外のメッセージに記述されています. (Either use a callable value for default or remove the timezone.) 前者は呼び出し可能オブジェクト (関数など) をデフォルト値に設定する方法で, 後者はタイムゾーン情報のない datetime オブジェクトを設定するというものです. 後者を採用するのはあまり好ましくないケースが多いと思うますが, 修正したモデルは以下のようになります.
from datetime import datetime
from django.db import models
from django.utils.timezone import now
class SampleModel(models.Model):
added = models.DateTimeField(default=datetime.utcnow())
updated = models.DateTimeField(default=now)
updated の方は前者の方法を用い, 関数をデフォルト値に設定しています. added の方は datetime.datetime.utcnow が tzinfo = None (タイムゾーン情報のない) の datetime オブジェクトを返すことを用いています.