Django Queryset过滤反向外键

Jul*_* A. 58 django model filter django-queryset

我有以下Django模型:

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

class MakeContent:
   make = models.ForeignKey(Make)
   published = models.BooleanField()
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以(不直接编写SQL)生成一个包含所有Makes和每个相关MakeContents的查询集published = True.

Jas*_*sta 60

是的,我想你想要的

make = Make.objects.get(pk=1)
make.make_content_set.filter(published=True)
Run Code Online (Sandbox Code Playgroud)

或者可能

make_ids = MakeContent.objects.filter(published=True).values_list('make_id', flat=True)
makes = Make.objects.filter(id__in=make_ids)
Run Code Online (Sandbox Code Playgroud)

  • 如果我没弄错的话,`.values`应该用`.values_list`代替. (5认同)
  • 您的第一个代码片段不起作用。它获取*一个* make 的所有 MakeContents,其中需要所有 Makes 的 MakeContents。_set 适用于单个对象,但不适用于查询集。 (2认同)
  • pintoch, flat=True 不提供与唯一性相关的任何内容。当只请求一个字段时,它只会导致返回单个值,而不是元组。 (2认同)

use*_*513 16

我知道这是一个非常古老的问题,但我正在回答.我认为我的答案可以帮助别人.我已经改变了模型如下.我用过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()
Run Code Online (Sandbox Code Playgroud)

我使用了以下查询集.

Make.objects.filter(makecontent__published=True)
Run Code Online (Sandbox Code Playgroud)

希望它会有所帮助.

  • 当有多个MakeContent指向同一个Make时,这将复制Make条目。诸如“从make select中进行选择”之类的内容在make.id = makecontent.make_id上​​加入makecontent,其中MakeContent中的多行具有相同的make_id。 (4认同)
  • 您可以使用Make.objects.filter(makecontent__published = True).distinct() (3认同)

SYK*_*SYK 15

让我将Spike的措辞答案翻译成未来观众的代码.请注意,每个'Make'可以有零到多个'MakeContent'

如果提问者意味着用AT LEAST ONE'MakeContent' 查询'Make',其发布= True,那么Jason Christa的第二个片段就会回答这个问题.

该片段相当于

makes = Make.objects.select_related().filter(makecontent__published=True).distinct()
Run Code Online (Sandbox Code Playgroud)

但是,如果提问者意味着使用其发布的='生成'的所有 'MakeContent' 来查询'Make' ,那么请按照上面的'make'进行操作,

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)
Run Code Online (Sandbox Code Playgroud)

包含所需的查询.


Spi*_*ike 12

Django不支持select_related()反向外键查找的方法,因此在不离开Python的情况下,您可以做的最好的事情是两个数据库查询.第一个是抓住所有Makes包含MakeContents在哪里published = True,第二个是抓住所有的MakeContents地方published = True.然后,您必须循环并按您希望的方式排列数据.这是一篇关于如何做到这一点的好文章:

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

  • 请参阅prefetch_related()方法,以简化您提到的两个查询. (2认同)