読者です 読者をやめる 読者になる 読者になる

Django Queryset AggregationでDBによって結果が異なるケース

django

DBがmysqlsqliteかによって、テストが落ちたり成功したりするケースがあったので原因をメモしておく


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)