Django ORM将孩子的数量分组
鉴于以下models.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')))
我想访问父级模型/视图到父级孩子的分组计数。
例如
parent.num_ok, parent.num_failed
要么
parent.child_counts_per_status['ok']
计数需要在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()
以下将按照您的建议,使用名为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)
如果你想为特定的父母(比如parent1)计数'ok'的孩子,请使用
parent1.children.filter(status='ok').count()
如果您需要为所有父母计数好的孩子,那么您可以使用注释,例如为每个父母打印孩子计数,您将使用
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
分别为您将使用的queryset
Parent.objects.filter(children__status='ok').distinct()
(我们使用不同来消除重复)
链接地址: http://www.djcxy.com/p/60213.html