Django Queryset AggregationでDBによって結果が異なるケース
DBがmysqlかsqliteかによって、テストが落ちたり成功したりするケースがあったので原因をメモしておく
- Max OSX 10.9.4
- MySQL 5.5.20
- python 2.7.5
- django 1.7
- MySQL-python 1.2.5
DateTimeFieldを持つモデル
from django.db import models class Entry(models.Model): last_updated = models.DateTimeField(auto_now=True)
aggregateした結果、
qs = Entry.objects.all().aggregate(Max('last_updated'), Min('last_updated')) print qs["last_updated__max"] print qs["last_updated__min"]
MySQLの場合
2014-09-23 04:34:32+00:00 2014-09-23 04:34:32+00:00
sqliteの場合
2014-09-23 04:33:54.706257+00:00 2014-09-23 04:33:54.706257+00:00
以上のようにMySQLの場合はmicrosecondが取得されていなかった
なので以下のサンプルのようなテストはsqliteでは通るがmysqlでは通らないことになる。
class EntryTest(TestCase): def test_save(self): entry = Entry.objects.create() qs = Entry.objects.all().aggregate(Max('last_updated'), Min('last_updated')) self.assertEquals(qs["last_updated__max"], entry.last_updated) self.assertEquals(qs["last_updated__min"], entry.last_updated)
本番で使用するDBで通るようにテストを書けばよいと思うけど、microsecondを0に合わせてやれば、mysqlでもsqliteでも通すことはできる。
class EntryTest(TestCase): def test_save(self): entry = Entry.objects.create() qs = Entry.objects.all().aggregate(Max('last_updated'), Min('last_updated')) expected = entry.last_updated.replace(microsecond=0) self.assertEquals(qs["last_updated__max"].replace(microsecond=0), expected) self.assertEquals(qs["last_updated__min"].replace(microsecond=0), expected)