きつねたぬきだし

ちょっとしたメモ代わりに。

Django の ORM の Date でハマってる

バージョンとか

まだ解決していないので、ざっくりした記事です。

(追記 2013/01/15 解決しました!現在記事作成中です。)

解決したら、ざっくりした生地をふわふわした記事に焼き上げます。

バージョンは以下の通りです。

検証したこと

こんなモデルを Django で作りました。

from django.db import models


class Foo(models.Model):
    date = models.DateField()


class Bar(models.Model):
    foo = models.ForeignKey(Foo)

さっそく、

python manage.py syncdb

して、

python manage.py shell

で試してみましょう。

>>> import sampleapp.models
>>> _query = Bar.objects.filter(foo__date__gt='2013-01-01').query
>>> print(_query)
SELECT `sampleapp_bar`.`id`, `sampleapp_bar`.`foo_id` FROM `sampleapp_bar` INNER JOIN `sampleapp_foo` ON (`sampleapp_bar`.`foo_id` = `sampleapp_foo`.`id`) WHERE `sampleapp_foo`.`date` > 2013-01-01 
>>>

見ての通り、 2013-01-01 にクオートがありません。非常に怖いですね。 実際にデータを処理してみましょう。

以下のように、 1 件のデータを入れてみました。

bar

idfoo_id
11

foo

iddate
12012-03-01

このデータだと、 2013-01-01 は 2012-03-01 よりも大きい(新しい)ので、ヒットしないはずです。

しかし、上のクエリを直接実行してみると、bar の id=1 がヒットします。 なぜなら、 2013-01-01 が評価され、 2013 - 1 - 1 = 2011 となるからです。

クエリ中の日付をシングルクオートで囲み、 '2013-01-01' とすると、正しい 0 件ヒットとなります。 MySQL 側の仕様としては、日付リテラルの挙動はこれで正しいはずです。

さらにこれは query がおかしいだけではなく、実際に QuerySet からの参照時も、このような動作になっているようです。 また、比較用の値を、 DateField の date や datetime.date にした場合の動作も同様でした。 (それぞれ、検証用のコードはまだ整理しておりません。)

date だけでなく、 datetime でも比較してみると面白いかもしれないです。

Django について自分の理解が足りていないだけなのかもしれず、ちょっと困惑中です。

詳細をご存知のかたおられましたら、ツッコミよろしくお願いします。