Django查询集,支持反向外键过滤

s3fp2yjn  于 2023-01-14  发布在  Go
关注(0)|答案(5)|浏览(197)

我有以下Django模型:

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

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

我想知道是否有可能(不直接编写SQL)生成一个包含所有Make和每个相关MakeContent的查询集,其中published = True

lvjbypge

lvjbypge1#

是的,我想你想

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)
muk1a3rh

muk1a3rh2#

我知道这是一个很老的问题,但我还是要回答。因为我认为我的答案可以帮助其他人。我已经改变了模型如下。我使用了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)

应使用distinct()以避免重复结果。

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

希望能有所帮助。

lnlaulya

lnlaulya3#

Django不支持用select_related()方法进行反向外键查找,所以在不离开Python的情况下,最好的方法是两个数据库查询:第一个是获取所有包含MakeContentsMakes,其中published = True,第二个是获取所有的MakeContents where published = True。然后你必须循环并按照你想要的方式排列数据。这里有一篇关于如何做到这一点的好文章:
http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

alen0pnh

alen0pnh4#

让我把斯派克的回答翻译成代码,以供未来的观众使用。请注意,每个“Make”可以有零到多个“MakeContent”
如果提问者想要查询“Make”,其中至少一个'MakeContent'的published=True,那么Jason Christa的第二个代码片段回答了这个问题。
该代码段等效于

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

但是如果请求者想要用ALL'MakeContent'查询'Make','MakeContent'的published=True,那么按照上面的'maks',

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)

包含所需的查询。

dgsult0t

dgsult0t5#

再说一次,我们不清楚问题是什么,但是如果希望所有相关的MakeContent对象都必须已经发布,那么这是可行的:

Make.objects.exclude(MakeContent_set__published=False)

如果其中至少有一个(因为它是在其他答案):

Make.objects.filter(MakeContent_set__published=True)

相关问题