ForeignKeyとfilterのメモ

自己責任で

あってるか検証しようとして簡単なModelつくろうとしたけどなんかうまくいかないからメモがき

ForeignKeyは1:Nなのは知ってる

  • BlogModelが1としてEntryModelがNならEntryModelにForeignKeyをはる
  • この場合 blog.entrymodel_set でクエリセットがとれる
    • modelを小文字で、 _set をつける。_setがついているほうがNである

filterの複合

  • 普通にチェインするなら ObjModel.objects.filter(name=name).filter(user=user)とかできる
  • 複合する場合は ObjModel.objects.filter(name=name, user=user)とする
    • 具体的には ObjModel.objects.filter(blog__in=entry.blog_set.all(), status__in=[1,2,3]) とかする。あるblogセットかつstatusが1,2,3であるクエリセット

追記 2012/08/01

filterでチェインするところは実際にクエリを確かめたらどうも where 以下を書き換えてるだけで、「,」で区切っても同じ意味かもしれない。というか同じっぽい。pdb;pdb.set_trace()でデバッガ仕込んで、 print ObjModel.objects.filter(name='hoge').query みたいにしてやるとクエリがみれるようだ。
実例

(Pdb) print User.objects.filter(nickname='hoge', email='moge').query
SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_active", "User"."ctime", "User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge )
(Pdb) print User.objects.filter(nickname='hoge').filter(email='moge').query
SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_active", "User"."ctime", "User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge )

@xxxxxxxxxx
python manage.py shell でシェル起動して from django.db import connection して なんか適当にモデルインポートして知りたいクエリ実行して connection.queries 叩くとSQL見られますよ

なるほど、こういう方法もあると。

(hoge)[02:52:27 atasatamatara@dev (hg:default) ~/qa-prj]$ py manage.py shell
>>> from qa.models import User
>>> from django.db import connection
>>> User.objects.filter(nickname='hoge', email='moge')
[]
>>> connection.queries
[{'time': '0.002', 'sql': u'SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_activ
e", "User"."ctime", "User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge ) LIMIT 21'}]
>>> User.objects.filter(nickname='hoge').filter(email='moge')
[]
>>> connection.queries
[{'time': '0.002', 'sql': u'SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_activ
e", "User"."ctime", "User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge ) LIMIT 21'}, {'time': '0.000', 's
ql': u'SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_active", "User"."ctime", "
User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge ) LIMIT 21'}]
>>> connection.queries[1]
{'time': '0.000', 'sql': u'SELECT "User"."id", "User"."email", "User"."password", "User"."nickname", "User"."bucho_point", "User"."is_active
", "User"."ctime", "User"."utime" FROM "User" WHERE ("User"."nickname" = hoge  AND "User"."email" = moge ) LIMIT 21'}

つまり shell しているあいだ connection が貼られていて、それを明示的に呼び出すために import して、 connection.queries で今まで発行したクエリが配列に格納されている、ということか。
参考:: http://kk6.hateblo.jp/entry/2012/08/01/Djangoの発行する生SQLが見たい
で次の話。ForeignKeyでmodel_setでとってこれるって話はあくまでインスタンスになっていることが前提っぽい(というかよく考えたら当たり前だ。インスタンスに紐付いていないものにたいしてどうクエリが発行できるのだ)。つまり上記の例で言うとあらかじめ entry という変数に Entryモデルのインスタンスをいれておくことで entry.blog_set が呼べるし、実際 entry.blog_set.all()で blog_setの中身が取れる .all() で呼んでるけど実際はクエリセットみたいなもの(実際はdjango.db.models.fields.related.RelatedManager object だ、そうだ)なので、only()とか .values() とか .order_by() とかも使える。