聚合查询方法名aggregate(),返回的是一个字典,不是queryset,而annotate()返回的是一个queryset,
2个方法区别是aggregate是对一组值进行计算,而annotate更多的是一组值进行group by后再进行计算.
聚合方法需要搭配具体计算的方法一起使用,需要导入avg max min count from django.db.models import Count,Avg,Max,Min
计算书本的平均价格,返回值的key值为 `字段__avg`,
book = models.Book.objects.all().aggregate(Avg("price")) #{'price__avg': Decimal('31.593333')}
也可以自定义key值
book2 = models.Book.objects.all().aggregate(avg_price =Avg("price")) #{'avg_price': Decimal('31.593333')}
分组查询
ORM中,book.Object.all() 等于sql语句的select * from book
,而book.Object.all().values("publish")等于sql语句的select publish from book
,
ORM中的values有2种意思,一个是只提取publish字段显示,如果Book.objects.values("publish_id").annotate 后面跟了聚合函数,也会按照该字段进行分组.
所以Book.objects.all().annotate 是一句没有意义的聚合命令,因为all()里面包含了id,每条记录都是不同的,因此无法产生按照特定字段进行聚合.
比如emp表,需要统计各个部门的人数
emp:
id name age dep
1 alex 18 销售部
2 blex 38 销售部
3 clex 28 市场部
4 dlex 48 客服部
sql语句
select Count(id) from emp group by dep; 通过对dep字段分组,再对每组的id个数进行统计
单表中的分组查询
orm中分组是用annotate(),返回值是一个query set
使用语法是前面先用value("dep").annotate(Avg("age"))
value("dep") 等于明确按dep分组,语法等同于group by dep
例子:
avg_age = models.Book.objects.values("publish_id").annotate(zidingyi =Avg("price")) #key值和aggregate一样可以自定义
# QuerySet[{'publish_id': 1, 'zidingyi': Decimal('38.275000')}, {'publish_id': 2, 'zidingyi': Decimal('18.230000')}]
跨表之组合查询
# 跨表分组查询模板
# 每一个后表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段)).values("表模型中的所有字段或者需要统计的字段")
# 每一个后表模型.objects.annotate(聚合函数(关联表__统计字段)).values("表模型中的所有字段或者需要统计的字段")
# 每一个后表模型.objects.all().annotate(聚合函数(关联表__统计字段)).values("表模型中的所有字段或者需要统计的字段")
上面第二个和第三个效果等同,因为values("pk")只是选择了pk这个字段,同时带有按这个字段group by的效果
但是我们用all()或者省略不写,ORM的语法意思是按照这个对象的所有字段进行group by的意思.
例1:查询出版社的名称以及出版的书本个数
sql语句示例
select my_book_publish.name,Count(my_book_book.title) from my_book_book inner join my_book_publish on my_book_book.publish_id = my_book_publish.pid group by my_book_publish.pid;
ORM语句示例
以publish为基表有三种写法,推荐用第二种,因为pid是唯一的,而有时候如果name会有重复,比如name为人名的时候
pub = models.Publish.objects.values("pid").annotate(c =Count("book__title"))
#< QuerySet[{'pid': 1, 'c': 3}, {'pid': 2, 'c': 2}, {'pid': 3, 'c': 1}] >
# group by pid,然后annotate通过反向查询 表名__字段 对该字段进行聚合计算,但是结果只显示出版社的pid
pub = models.Publish.objects.values("pid").annotate(c=Count("book__title")).values("name","c")
#<QuerySet [{'name': '南京出版社', 'c': 3}, {'name': '北京出版社', 'c': 2}, {'name': '浙江出版社', 'c': 1}]>
# 因为前面语句已经把2张表拼成了一张表,里面除了出版社和book的字段,c 这个计算结果字段也会包含在内,所以我们要显示出版社name和c可以再加个values进行展示
pub = models.Publish.objects.values("name").annotate(c=Count("book__title"))
# group by name,然后annotate通过反向查询 表名__字段 对该字段进行聚合计算
# <QuerySet [{'name': '南京出版社', 'c': 3}, {'name': '北京出版社', 'c': 2}, {'name': '浙江出版社', 'c': 1}]>
例2:查询每一个作者的名字以及他们出版过书籍的最高价格
sql语句: select name,MAX(price) from my_book_book inner join my_book_book_author on my_book_book.id = my_book_book_author.book_id inner join my_book_author on my_book_book_author.author_id = my_book_author.aid group by aid
pub = models.Author.objects.values("pk").annotate(c = Max("book__price")).values("name","c")
#models.Author.objects.values("pk").annotate(c = Max("book__price"))等于是把author ,book author_book三张表join成了一张,后面可以选择要显示的内容
#<QuerySet [{'name': 'blex', 'c': Decimal('28.23')}, {'name': 'clex', 'c': None}, {'name': 'alex', 'c': Decimal('28.23')}]>
例3: 查询每一个书籍的名称和对应的作者个数
sql语句:
#select title,count(aid) as "作者个数" from my_book_book inner join my_book_book_author on my_book_book.id = book_id inner join my_book_author on my_book_book_author.author_id = my_book_author.aid group by book_id;
pub = models.Book.objects.values("pk").annotate(c = Count("author__aid")).values("title","c")
#Count("author__aid")这里的author是字段不是表名,因为book下本来就有author字段,正向查找按字段
#<QuerySet [{'title': 'python', 'c': 2}, {'title': 'java', 'c': 2}, {'title': 'c++', 'c': 0}, {'title': 'go', 'c': 0}, {'title': 'c#', 'c': 0}, {'title': 'php', 'c': 0}]>
#我们也可以通过book查其他表下的字段,语法: 字段(表名)__字段
pub=models.Book.objects.values("pk").annotate(c=Count("author__name")).filter(c__gt=1).values("title","publish__name")