使用子对象字段筛选查询集



我有两个模型Parent,Child

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

我们可以排除存在不需要的子级的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')
)

因此,我们首先计算相关Childs的数量,并且还将具有wanted的相关Childs的数量设置为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. 在子模型中给出与父相关的名称:

parent=模型。ForeignKey(Parent,…,related_name="children"(

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

Parent.objects.filter(children__want=True(.exclude(children_want=False(

或者您可以调用Parent.objects.exclude(children__want=False(,以防此布尔值不可为null。

最新更新