web-dev-qa-db-ja.com

Django逆方向外部キーでフィルタリングしたクエリセット

私は次のDjangoモデルを持っています:

class Make:
   name = models.CharField(max_length=200)

class MakeContent:
   make = models.ForeignKey(Make)
   published = models.BooleanField()

すべてのMakesおよび関連するMakeContentsがpublished = Trueであるクエリセットを生成できるかどうか(SQLを直接記述することなく)知りたいのですが。

53
Julian A.

Djangoは、外部キーの逆引き参照のためのselect_related()メソッドをサポートしていないため、Pythonを残さずにできる最善の方法は、2つのデータベースクエリです。 Makesを含むMakeContentsここで、published = True、2番目はすべてのMakeContentsを取得することです。ここでpublished = True。次に、ループしてデータを希望どおりに配置する必要があります。これを行う方法についての良い記事があります:

http://blog.roseman.org.uk/2010/01/11/Django-patterns-part-2-efficient-reverse-lookups/

11
Spike

はい、あなたが欲しいと思います

make = Make.objects.get(pk=1)
make.make_content_set.filter(published=True)

または多分

make_ids = MakeContent.objects.filter(published=True).values_list('make_id', flat=True)
makes = Make.objects.filter(id__in=make_ids)
58
Jason Christa

スパイクの言葉による答えを将来の視聴者向けのコードに翻訳させてください。各「Make」には、ゼロから複数の「MakeContent」を含めることができます。

質問者が「作成」を照会することを意味する場合 少なくとも一つの published = Trueの 'MakeContent'の場合、Jason Christaの2番目のスニペットが質問に答えます。

スニペットは次と同等です

makes = Make.objects.select_related().filter(makecontent__published=True).distinct()

しかし、質問者が「Make」を照会することを意味する場合 すべて published = Trueである「MakeContent」、上記の「makes」に続いて、

import operator
make_ids = [m.id for m in makes if 
    reduce(operator.and_, [c.published for c in m.makecontent_set.all()] ) 
]
makes_query = Make.objects.filter(id__in=make_ids)

目的のクエリが含まれています。

14
SYK

これは非常に古い質問ですが、答えています。私の答えは他の人を助けることができると思います。モデルを次のように少し変更しました。 Django 1.8。

class Make(models.Model):
    name = models.CharField(max_length=200)

class MakeContent(models.Model):
    make = models.ForeignKey(Make, related_name='makecontent')
    published = models.BooleanField()

次のクエリセットを使用しました。

Make.objects.filter(makecontent__published=True)

それが役立つことを願っています。

14
user1012513