2011-03-25 72 views
39

我有以下的Django模型:Django的查詢集與過濾相反的外鍵

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

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

我想知道這是否是可能的(不直接寫SQL)對我產生一個包含所有Make一個QuerySet s和每個人的相關MakeContent s其中published = True

+0

你能對你的問題更具體嗎? – pyeleven 2011-03-25 20:08:15

回答

9

Django不支持用於反向外鍵查找的select_related()方法,所以在不離開Python的情況下最好做的是兩個數據庫查詢。首先是抓取包含MakeContents的所有Make,其中published = True,第二個抓取所有MakeContents,其中published = True。然後,您必須循環並安排數據的方式。下面是關於如何做到這一點的好文章:

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

+18

不要以爲我現在需要回答這個問題...... – 2011-03-25 20:16:03

+2

請參閱prefetch_related()方法,以簡化您提到的兩個查詢。 – 2013-03-19 17:19:45

42

是的,我想你想

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) 
+3

如果我沒有弄錯,'.values'應該替換成'.values_list'。 – exfizik 2012-01-08 06:26:12

+1

你的第一個代碼段不起作用。它獲取* one * make的所有MakeContents,其中MakeContents for all Makes是必需的。 _set適用於單個對象,但不適用於查詢集。 – knite 2012-09-07 00:18:58

+0

添加'flat = True'有什麼意義?根據定義,ID已經是唯一的,並且確保它們是唯一的可能需要一些額外的計算。 – pintoch 2014-09-27 19:29:08

9

讓我釘的措辭回答轉化爲代碼未來的觀衆。請注意,每個「製作」可以有零到多個「MakeContent」

如果提問者表示查詢「製作」與至少一個「MakeContent」,其公佈= true,則傑森克里斯塔的第2段回答了這個問題。

的片段相當於

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

但如果提問者表示查詢 '製作' 與ALL 'MakeContent',其公佈= true,則繼 '讓' 上面,

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) 

包含所需的查詢。

4

我知道這是一個很老的問題,但我正在回答。我想我的答案可以幫助別人。我已經改變了一下模型。我用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) 

希望它會有所幫助。