我有两个模型父母,孩子
class Parent(models.Model):
id = models.IntegerField(...)
class Child(models.Model)
id = models.IntegerField(...)
parent = models.ForeignKey(Parent, ...)
wanted = models.CharField(default="yes")
我想过滤所有与该父母一起出现的孩子将“通缉”为“是”的所有父对象
我的代码:
def containsYes(self):
yes_ids = []
qs = self.get_queryset()
for q in qs:
children = Child.objects.filter(parent_id = q.id)
count = children .count()
if children.filter(wanted = 'yes').count() == count
yes_ids.append(q.id)
return qs.filter(id__contains = yes_ids)
我知道这段代码非常低效,并且想要一个仅使用查询的更好的解决方案
PS:我是 Django 新手
答案 0 :(得分:0)
我们可以排除 Parent
存在不想要的孩子的地方,因此我们可以使用:
from django.db.models import F, Count, Q
Parent.objects.annotate(
nchild=Count('child')
nchild_wanted=Count('child', filter=Q(child__wanted=True))
).filter(
nchild=F('nchild_wanted')
)
因此,我们首先计算相关 Child
的数量,并将与 Child
相关的 wanted
数量设置为 True
。然后我们过滤并仅保留这两个注释相同的 Parent
对象。
由于 django-3.2,可以使用 .alias(…)
[Django-doc] 来防止在 SELECT
子句和 HAVING
子句中计数:
from django.db.models import F, Count, Q
Parent.objects.alias(
nchild=Count('child')
nchild_wanted=Count('child', filter=Q(child__wanted=True))
).filter(
nchild=F('nchild_wanted')
)
答案 1 :(得分:0)
parent = models.ForeignKey(Parent, ..., related_name="children")
Parent.objects.filter(children__wanted=True).exclude(children__wanted =False)
或者你可以调用 Parent.objects.exclude(children__wanted=False) 情况下这个布尔值不是可以为空的字段。