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


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

    示例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
    
  • 相关阅读:
    python变量和常量
    python运算符
    python 数据类型强制转换
    Python 变量的缓存机制
    Python格式化输出
    Python 自动类型转换
    Python 六大标准基础数据类型
    Python 基础
    pyhton 初识
    计算机基础
  • 原文地址:https://www.cnblogs.com/thomaszdxsn/p/Django-ORM-zhong-ru-he-shi-yongCount-lai-ji-suan-g.html
Copyright © 2020-2023  润新知