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
id | foo_id |
---|---|
1 | 1 |
foo
id | date |
---|---|
1 | 2012-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 について自分の理解が足りていないだけなのかもしれず、ちょっと困惑中です。
詳細をご存知のかたおられましたら、ツッコミよろしくお願いします。