Django ORM中,如何使用Count来关联对象的子集数…

2019-04-11 10:14:21来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

  • 示例models
  • 解决方法

有时候,我们想要获取一个对象关联关系的数量,但是我们不要所有的关联对象,我们只想要符合规则的那些关联对象的数量。

示例models

# models.py
from django.db import models


class Person(models.Model):
    name = models.CharField('名称', max_length=32)
        
    def __str__(self):
        return self.name
        
        
class Task(models.Model):
    name = models.CharField('任务名称', max_length=64)
    is_done = models.BooleanField('是否完成', default=False)
    owner = models.ForeignKey(Person, verbose_name='任务执行人')
    
    def __str__(self):
        return "{}({})".format(self.name, 'x' if self.is_done else 'o')

上面的代码中,我们使用了两个model,PersonTask。它们是一对多关系,一个用户可能有多个任务。

那么,我们怎么来获取一个用户已完成任务的数量呢?

解决方法

一般来说,都是使用下面这个办法:

>>> person = Person.objects.first()
>>> person.task_set.all().count()
15
>>> person.task_set.filter(is_done=True).count()
10

这个办法,确实可以解决问题。但是如果你有很多Person,都需要获取已完成任务的数量,使用这个方法会依次对每个person的tasks集合使用单独的SQL,开销极大。

我们知道,Django ORM有一个aggregate函数,叫做Count。一般情况下,可以用它来获取一个对象关联对象的数量,并生成一个额外的computed字段。而在Django2.0中1Count新加入了一个参数filter,使用它,可以在计算count数量之前先对集合进行过滤

>>> from django.db.models import Count, Q
>>> person = Person.objects.annotate(
...             Count('task_set', filter=Q(task_set__is_done=True))
...         ).first()
>>> person.task_set__count
10

而在Django2.0之前,我们应该怎么办呢?可以用SQL的Case/When来解决:

>>> from django.db.models import Count, When, Case
>>> person = Person.objects.annotate(Count(Case(When(task_set__is_done=True, then=0))).first()
>>> person.task_set__count
10

  1. Django API Reference: Count ↩


原文链接:https://www.cnblogs.com/thomaszdxsn/p/Django-ORM-zhong-ru-he-shi-yongCount-lai-ji-suan-g.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:计数排序与桶排序python实现

下一篇:pytest使用问题总结