使用子对象字段过滤查询集

时间:2021-06-17 05:47:42

标签: python django django-queryset

我有两个模型父母,孩子

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 新手

2 个答案:

答案 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 对象。

由于 ,可以使用 .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)

  1. 在子模型中给出与父相关的名称:

parent = models.ForeignKey(Parent, ..., related_name="children")

  1. 将 Wanted 字段更改为布尔值并将其默认为 True,然后您可以执行以下操作:

Parent.objects.filter(children__wanted=True).exclude(children__wanted =False)

或者你可以调用 Parent.objects.exclude(children__wanted=False) 情况下这个布尔值不是可以为空的字段。