MawaLog

一日一日、楽しく生きる。技術と音楽が好き。

Djangoで逆参照したクエリセットを得るコード

Django逆参照とは

例えばこういうモデルを作っているとする。

・親model 子modelからForeignKeyなしのモデル
・子model ForeignKey(親model)

普通の参照(順参照とここでは定義しておく)は、子modelから親modelの参照をテンプレート内では"."、view関数内では"__"をつけて参照するのだが、親モデルから小モデルの状況に応じてクエリセットをつくりたいときは逆参照ということになる。より一般的にに書くと、親modelオブジェクト順に、親modelの参照されている子modelのオブジェクトを並べたクエリセットがほしいというときは逆参照という操作をやらざるを得ないのであるが、順参照とはコードがちょっと・・・いや、かなり違うのでメモしておく。

どうもPrefechというオブジェクトをつくって、prefech_relatedを使うと一番効率が良いらしい・・・(この辺は、完全な理解はまだなので、どういうものか現象面の説明は、この記事ではできない。今回はこれで希望がかなうコード構成になりますよ ということだけに絞って書きます)

Prefechオブジェクトを用いた逆参照クエリ生成を実装

と、いうことで参考記事にならい、Prefetchなどをインポートし、以下のように書く。

from hoge.models import *
from django.db.models import Prefetch

<親model名>.objects.all().prefetch_related(Prefetch("<子model名>_set", queryset=<子model名>.objects.all().order_by("pubdate"), to_attr="<同じ親model参照している子modelオブジェクトの固まりにつけるグループ名(例:group なんでもいいけど・・・)>")):

これで逆参照が比較的少ないクエリ発行量で実現できる(模様)。

いつものようにprintで動作確認

というわけで、上手く動いているか確認するためには、クエリの各かたまり(こんかいは"group"という属性を与えた("to_attr"で)もの)

for obj in <親model名>:
    print(len(obj.group))

参照されている親modelオブジェクトごとの子modelオブジェクト数がカウントされた値がprintされる。だから例えばまったく参照されてない親モデルの子modelオブジェクトは0個なのでlen(obj.group)も0である、と検証できる。だから、参照がされてないものは最初から弾いてlistつくろうかなというときは、

list = []
for obj in <親model名>:
    if len(obj.group)) > 0:
        list.append(obj)

というようにすれば良い。

逆参照オブジェクトの扱いで登場しやすいlistのDjangoテンプレート上の参照方法

ちなみに

list = [[hoge,fuga],[foo,bar]]

Djangoテンプレート上での参照は、 list.0、list.1のように書くのでlist[0][0]とかで反応しないので気をつけてください

参考にさせていただいた記事

qiita.com