django 版本 3.2
python 3.6.8
常见的五个聚合函数:
from django.db.models import Avg, Max, Min, Sum, Count, Q, F
# Q查询和F查询也可以一起导入,一般会经常频繁使用
以上五个聚合函数都可以在 aggregate 和 annotate 中使用。
aggregate()是QuerySet 的一个终止子句,也就是说在写QuerySet 查询语句时aggregate()后面不能再有其他查询语句,因为aggregate()会返回一个键值对的字典,不再是QuerySet 对象。
使用方法如下:
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')}
使用方法如下:
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'))
上面的聚合查询其实经常需要先分组再查询,那么就会用到 annotate
annotate查询的结果不是键值对的字典,但是一个queryset列表对象,而列表中的元素是字典格式,可以向列表和字典一样取值,因此annotate的后面可以加其他查询语句,例如annotate(Avg(‘price’)) .values("***),但是这么写结果是annotate查询失效,比如:
queryset = models.MyModel.objects.annotate(Avg('price')) .values("***)
虽然这么写不会报错,但是这么写之后前面的annotate会失去作用!!! 所以网上很多帖子说values() 放前面是什么作用,放后面是什么作用,其实不然,放后面就失去了使用 annotate的意义了。而annotate的前面必须使用 .values().order_by() 先制定按哪个字段分组。
总结,annotate虽然返回的queryset对象,但是后面增加其他查询语句会导致annotate查询失效,因此说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'))
从方法一和方法二看出,order_by() 中写不写参数都可以,推荐方法一省略order_by()中的参数即可,原因请继续往下看:3.3
写法参考上面两种(但是推荐第一种)
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'))
上面两种写法,本人开始也认为是按order_by()种的参数排序分组,其实不然。经过本人实验,order_by()中不管写什么都会去拿values()中的所有字段去分组,所以说values()的作用就是指定分组的字段,order_by() 不需要写任何参数,因为写了也不起作用。
查询结果的键值对会包含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 )
# 打印结果:
之前由帖子提到,一条查询语句annotate中多次Count查询要使用distinct=True 其实已经没有用了,因为前面已经使用了values().order_by()进行了精确分组,所以在django版本3.2; python版本3.6.9 之中甚至之后都没有用了,本人也亲自试验了一下,得到的queryset对象不是字典对象也拿不到想要查询的数据。
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'))