django中aggregate和annotate的不同

结论: 

        1、两者都是进行聚合计算的

        2、aggregate 计算所有QuerySet 对象的一个汇总值,返回的是一个dict,annotate为QuerySet中的每个对象生成一个汇总,返回的还是一个QuerySet对象。

        3、如果转换成SQL语句的话:

    aggregate :select count(*) from user
    annotate :select count(*) from user group by gender

  4、因为aggregate返回的是一个dict,是没有办法进行链式编程了,所以没有办法再接QuerySet对象的其他方法。

案例:

from django.db import models
 
class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
 
class Publisher(models.Model):
    name = models.CharField(max_length=300)
 
class Book(models.Model):
    name = models.CharField(max_length=300)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    rating = models.FloatField()
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    pubdate = models.DateField()
 
class Store(models.Model):
    name = models.CharField(max_length=300)
    books = models.ManyToManyField(Book)

aggregate 进行聚合计算

# 计算Book的总数
>>> Book.objects.count()
2452
 
#计算出版社为BaloneyPress的书的总数
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73
 
# 计算所有图书的平均价格
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
 
# 获取最高图书价格
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}
 
# 计算最高价格和平均价格的差
>>> from django.db.models import FloatField
>>> Book.objects.aggregate(
...     price_diff=Max('price', output_field=FloatField()) - Avg('price'))
{'price_diff': 46.85}

annotate 进行聚合计算

>>> from django.db.models import Count
#计算每个出版社的图书数量
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
<QuerySet [<Publisher: BaloneyPress>, <Publisher: SalamiPress>, ...]>
>>> pubs[0].num_books
73
 
# 求每个出版社书籍评分大约5分和小于5分的图书量
>>> from django.db.models import Q
>>> above_5 = Count('book', filter=Q(book__rating__gt=5))
>>> below_5 = Count('book', filter=Q(book__rating__lte=5))
>>> pubs = Publisher.objects.annotate(below_5=below_5).annotate(above_5=above_5)
>>> pubs[0].above_5
23
>>> pubs[0].below_5
12
 
# 求出版社出最多书的前五名
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323

简单说明

django 提供两种产生聚合的方法

  第一种aggregate 方法是产生整个结果集的总体统计值。

  第二种方法,产生结果集中每个对象的独立的总体统计值。

  注意,结果集有多少对象就生成多少个统计值,这是aggregate()annotate()的主要区别。

理解这两个概念,就清楚怎么使用aggregate()annotate()这两个函数了。

 

上面是简单理解

  这两个函数除了在聚合方面存在差别以外,其实还是有很大的不同的。aggregate()只能支持聚合函数。annotate()支持functions下面的所有函数。

    from django.db.models.functions import TruncMonth
    models.Test.objects                        # 这里是手工折行的 ^_^
    .annotate(month=TruncMonth('timestamp'))   # 把2021-11-11转换成2021-11 并把month放入QuerySet中
    .values('month')                           # Group By month
    .annotate(c=Count('id'))                   # 根据month分组计数 并把c放入到QuerySet中 
    .values('month','c')                       # select month,c from QuerySet    ==>QuerySet

 

posted @ 2021-11-09 12:17  高中生物  阅读(114)  评论(0)    收藏  举报