Python Django ORM儿童分组计数

Python Django ORM儿童分组计数,python,django,orm,Python,Django,Orm,给定以下模型.py class Parent(models.Model): name = models.CharField(max_length=100) class Child(models.Model): parent = models.ForeignKey('Parent', related_name='children') status = models.CharField(max_length=10, choices=(('ok', 'ok'), ('fail

给定以下模型.py

class Parent(models.Model):
    name = models.CharField(max_length=100)

class Child(models.Model):
    parent = models.ForeignKey('Parent', related_name='children')
    status = models.CharField(max_length=10, choices=(('ok', 'ok'), ('fail', 'fail')))
我想在父模型/视图上访问父模型/视图的子对象的分组计数

e、 g

计数需要在SQL中完成,因为为所有父级加载所有子级,然后在内存中对它们进行计数会产生太大的开销,每个父级可能有数万个子级

如果我在ORM之外写这篇文章,我会这样做:

select parent.id, parent.name, child.status, count(*) from parent
inner join child on child.parent_id = parent.id
group by parent.id, parent.name, child.status
但是,鉴于我将通过分页限制家长人数,可以:

select parent.* from parent where ... (page is)
然后,每个父级执行一次:

select status, count(*) from child where parent_id = :parent_id
group by status
通过Django ORM是否可以使用这些选项中的任何一个

如果是的话。。如何将其插入到对象模型中?我使用的是Django Rest Framework,我猜查询将进入views.py,它目前看起来像:

class ParentViewSet(viewsets.ModelViewSet):

    queryset = Parent.objects.all()

如果您想获得特定父级(如parent1)的“ok”子级计数,请使用

parent1.children.filter(status='ok').count()
如果您需要计算所有家长的“ok”子女数,那么您可以使用,例如,要打印每个家长的子女数,您将使用

from django.db.models import Count 

parents = Parent.objects.filter(children__status='ok').annotate(c_count=Count('children'))

for p in parents:
  print p.c_count
Parent.objects.filter(children__status='ok').distinct()
分别用于您将使用的queryset

from django.db.models import Count 

parents = Parent.objects.filter(children__status='ok').annotate(c_count=Count('children'))

for p in parents:
  print p.c_count
Parent.objects.filter(children__status='ok').distinct()

我们使用消除重复

如果您想获得特定父级(如parent1)的“ok”子级计数,请使用

parent1.children.filter(status='ok').count()
如果您需要计算所有家长的“ok”子女数,那么您可以使用,例如,要打印每个家长的子女数,您将使用

from django.db.models import Count 

parents = Parent.objects.filter(children__status='ok').annotate(c_count=Count('children'))

for p in parents:
  print p.c_count
Parent.objects.filter(children__status='ok').distinct()
分别用于您将使用的queryset

from django.db.models import Count 

parents = Parent.objects.filter(children__status='ok').annotate(c_count=Count('children'))

for p in parents:
  print p.c_count
Parent.objects.filter(children__status='ok').distinct()

我们使用以消除重复

以下内容将按照您的建议,在名为num_ok和num_fail的属性中使用两种类型的子对象的计数来注释每个父对象

这会在内部创建与您建议的SQL几乎相同的SQL,这将计数留给数据库,而不是在Python或Django中完成

from django.db.models import Count, Case, When, IntegerField

...

queryset = Parent.objects.annotate(
               num_ok=Count(Case(
                            When(children__status='ok', then=1),
                                output_field=IntegerField()))
           ).annotate(
               num_fail=Count(Case(
                              When(children__status='fail', then=1),
                                output_field=IntegerField())))
这将允许您对父对象进行迭代,并按如下方式检索计数:

for parent in queryset:
    print(parent.num_ok)
    print(parent.num_fail)

下面将按照您的建议,使用名为num_ok和num_fail的属性中两种类型的子对象的计数来注释每个父对象

这会在内部创建与您建议的SQL几乎相同的SQL,这将计数留给数据库,而不是在Python或Django中完成

from django.db.models import Count, Case, When, IntegerField

...

queryset = Parent.objects.annotate(
               num_ok=Count(Case(
                            When(children__status='ok', then=1),
                                output_field=IntegerField()))
           ).annotate(
               num_fail=Count(Case(
                              When(children__status='fail', then=1),
                                output_field=IntegerField())))
这将允许您对父对象进行迭代,并按如下方式检索计数:

for parent in queryset:
    print(parent.num_ok)
    print(parent.num_fail)

谢谢接受了另一个答案,因为在现实生活中,如何处理同一数据库调用中的多个雕像更为清晰。我不止有两个,但这有助于我的总体理解。谢谢。我接受了另一个答案,因为在现实生活中,如何处理同一数据库调用中的多个雕像更为清晰,我不止有两个,但这有助于我的总体理解。