[英]Django ORM grouped count of children
鑒於以下模型
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()
如果要獲取特定父母(例如parent1)的“正常”孩子數,請使用
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()
(我們使用distinct來消除重復)
下面將按照您的建議,在名為num_ok
和num_fail
的屬性num_ok
兩種類型的子代的計數注釋每個父對象。
這在內部創建的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())))
這將允許您遍歷Parent對象並按以下方式檢索計數:
for parent in queryset:
print(parent.num_ok)
print(parent.num_fail)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.