• Django ORM查询之聚合函数、聚合查询(aggregate)、分组查询(annotate)


    django 版本 3.2
    python 3.6.8

    一、聚合函数

    常见的五个聚合函数:

    • Avg (Average) : 平均值
    • Max (Maximum) : 最大值
    • Min (Minimum) : 最小值
    • Sum (Summary) : 求和
    • Count : 个数
      导入语句:
    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    # Q查询和F查询也可以一起导入,一般会经常频繁使用
    
    • 1
    • 2

    以上五个聚合函数都可以在 aggregate 和 annotate 中使用。

    二、聚合查询 aggregate()

    2.1 aggregate() 终止子句

    aggregate()是QuerySet 的一个终止子句,也就是说在写QuerySet 查询语句时aggregate()后面不能再有其他查询语句,因为aggregate()会返回一个键值对的字典,不再是QuerySet 对象。

    2.2 使用方法,可自定义变量key

    使用方法如下:

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    queryset =  models.MyModel.objects.aggregate(Avg('price')) 
    print(queryset)  
    # 打印结果: {'price__avg': Decimal('34.204000')} 系统会字典生产一个由“变量名_方法名”组成的字典key,这样并不方便,我们可以自定义key,如下:
    queryset =  models.MyModel.objects.aggregate(my_key=Avg('price')) 
    print(queryset)  
    # 打印结果: {'my_key': Decimal('34.204000')} 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2.3 多个聚合函数一起查询

    使用方法如下:

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    queryset =  models.MyModel.objects.aggregate(Avg('price'),Max('price'),Min('price'),Sum('price')) 
    
    
    • 1
    • 2
    • 3
    • 4

    三、分组查询 annotate

    上面的聚合查询其实经常需要先分组再查询,那么就会用到 annotate

    3.1 annotate()不是终止子句但等于终止子句

    annotate查询的结果不是键值对的字典,但是一个queryset列表对象,而列表中的元素是字典格式,可以向列表和字典一样取值,因此annotate的后面可以加其他查询语句,例如annotate(Avg(‘price’)) .values("***),但是这么写结果是annotate查询失效,比如:

    queryset =  models.MyModel.objects.annotate(Avg('price')) .values("***)
    
    • 1

    虽然这么写不会报错,但是这么写之后前面的annotate会失去作用!!! 所以网上很多帖子说values() 放前面是什么作用,放后面是什么作用,其实不然,放后面就失去了使用 annotate的意义了。而annotate的前面必须使用 .values().order_by() 先制定按哪个字段分组。
    总结,annotate虽然返回的queryset对象,但是后面增加其他查询语句会导致annotate查询失效,因此说annotate()不是终止子句但是等于终止句子。(如果说法有误,欢迎试验后回复订正)

    3.2 使用方法,queryset.values(‘**’).order_by() .annotate()

    先声明一下django版本3.2; python版本3.6.9 下使用annotate必须按上面的固定写法,少一个都不行,可能不会报错,但是查询不到想要的结果。(可能之前的版本不需要如此,仅供思路参考)
    使用方法如下:

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    # 写法一
    queryset =  models.MyModel.objects.values('price').order_by().annotate(Count('price')) 
    # 写法二
    queryset =  models.MyModel.objects.values('price').order_by('price').annotate(Count('price')) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    从方法一和方法二看出,order_by() 中写不写参数都可以,推荐方法一省略order_by()中的参数即可,原因请继续往下看:3.3

    3.3 多字段分组 queryset.values(‘price’,‘name’).order_by() .annotate()

    写法参考上面两种(但是推荐第一种)

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    # 写法一
    queryset =  models.MyModel.objects.values('price''name').order_by().annotate(Count('price')) 
    # 写法二
    queryset =  models.MyModel.objects.values('price''name').order_by('price').annotate(Count('price')) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上面两种写法,本人开始也认为是按order_by()种的参数排序分组,其实不然。经过本人实验,order_by()中不管写什么都会去拿values()中的所有字段去分组,所以说values()的作用就是指定分组的字段,order_by() 不需要写任何参数,因为写了也不起作用。

    3.4 查询结果字典

    查询结果的键值对会包含values()中的参数和annotate()中聚合函数查询结果的key,例如:

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    # annotate 中不指定自定义key 
    queryset =  models.MyModel.objects.values('price''name').order_by().annotate(Count('price')) 
    print(queryset )
    # 打印结果:
    
    #  annotate 中指定自定义key 
    queryset =  models.MyModel.objects.values('price''name').order_by().annotate(my_count = Count('price')) 
    print(queryset )
    # 打印结果:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.5 关于annotate中多次使用聚合函数Count时的参数distinct=True

    之前由帖子提到,一条查询语句annotate中多次Count查询要使用distinct=True 其实已经没有用了,因为前面已经使用了values().order_by()进行了精确分组,所以在django版本3.2; python版本3.6.9 之中甚至之后都没有用了,本人也亲自试验了一下,得到的queryset对象不是字典对象也拿不到想要查询的数据。

    四、annotate 于 aggregate的区别

    1、终止子句
    aggregate 是终止子句,后面加任何查询语句都会报错。
    annotate 不是终止子句,后面加任何查询虽然不会报错,但会导致annotate 查询失效。
    2、
    简单的说 annotate 是先分组再聚合查询,aggregate 是仅仅聚合查询,即便在 aggregate 前面加上 annotate 前面相同的分组条件 values(‘**’).order_by() 也不会分组。

    from django.db.models import Avg, Max, Min, Sum, Count, Q, F
    
    # annotate 分组查询
    queryset =  models.MyModel.objects.values('price''name').order_by().annotate (my_count = Count('price')) 
    print(queryset )
    # 打印结果:  是个 QuerySet 列表对象,列表中的元素是字典格式,如果有多个分组,对象列表中会有多个字典元素
    
    
    #  aggregate 聚合查询
    queryset =  models.MyModel.objects.values('price''name').order_by().aggregate(my_count = Count('price')) 
    print(queryset )
    # 打印结果:{'price': '23', 'name': '张山', 'my_count ': '23'},直接就是个字典,即便有多个分组,也是相同的结果,aggregate只会统计相全部,不会按分组查询。因此上面的写法,等同于:
    queryset =  models.MyModel.objects.aggregate(my_count = Count('price')) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    工业品MRO采购网站有哪些优势?一文带你读懂
    虹科方案|具有RDMA复制写入日志的高可用性HDD存储集群可提供出色的性能
    比React—Redux和Redux好用100倍的原子级状态管理器,是我们公司自己封装的npm包,如果感兴趣可以研究研究,会大大提高开发效率
    【nodejs案例】记账本功能 -- 如何配置API(三)
    Redis 非关系型数据库 配置与优化
    【算法】二分查找模板
    【Python 自动化办公】docx module 的坑
    面试题:什么是this.$nextTick
    Html + Express 实现大文件分片上传、断点续传、秒传
    【数学建模】层次分析(Matlab&Python代码实现)
  • 原文地址:https://blog.csdn.net/wuwei_201/article/details/134528623