10 Django 聚合查询和分组查询
一、聚合查询
聚合(利用聚合函数查询):aggregate()
是QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
用到的内置函数:from django.db.models import Avg,Sum,MAx,Min,Count
示例:
form django.db.models import Avg,Sum,MAx,Min,Count
# 假设我们已经有书这张表了
# 查询所有的书的平均价格
models.Boook.objects.all().aggregate(Avg('prince'))
{'price__avg': xxxx}
如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
models.Book.objects.aggregate(average_price=Avg('price'))
{'average_price': xxxx}
如果你希望生成不止一个聚合,你可以向aggregate()
子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{'price__avg': xxx, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
二、分组查询
先来一起复习一下SQL原生语句的分组把
假设现在有一张公司职员表:
我们要使用SQL原生语句,按照部门分组求平均工资:
select dept Avg(salary) from employee group by dept
ORM查询:
from django.db.models import AVG
Employee.objects.values("dept").annotate(avg=Avg('salary')).values(dept,'dept_avg')
这里需要注意的是annotate分组依据就是他前面的值,
如果前面没有特点的字段,则默认按照ID分组,
这里有dept字段,所以按照dept字段分组
连表查询的分组:
SQL原生语句查询
select dept.name,Avg(salary) from employee inner join dept on(employee.dept_id=dept.id) group by dept_id
ORM查询:
from django.db.models import AVG
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
示例合集
示例1:统计每本书的作者个数
book_list = models.Book.objects.annotate(num=count('author_id')).value('name',"num")
for obj in book_list:
print(obj.author_num)
示例2:统计出每个出版社最便宜的书的价格
#方法一:
publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
for obj in publisher_list:
print(obj.min_price)
#方法二:
models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
示例3:统计不止一个作者的图书
book_obj=models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
print(obj)
示例4.查询各个作者出的书的总价格
res = models.Author.objects.annotate(price_sum = Sum("book__price")).values("price_sum")
print(res)
示例5:根据一本图书作者数量的多少对查询集 QuerySet进行排序
models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
总结
value里面的参数对应的是sql语句中的select要查找显示的字段,
filter里面的参数相当于where或者having里面的筛选条件
annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值