Django中Aggregation聚合的基本使用方法


Posted in Python onJuly 09, 2020

Django 的 filter、exclude 等方法使得对数据库的查询很方便了。这在数据量较小的时候还不错,但如果数据量很大,或者查询条件比较复杂,那么查询效率就会很低。

提高数据库查询效率可以通过原生 SQL 语句来实现,但是它的缺点就是需要开发者熟练掌握 SQL。倘若查询条件是动态变化的,则编写 SQL 会更加困难。

对于以便捷著称的 Django,怎么能忍受这样的事。于是就有了 Aggregation聚合 。

聚合最好的例子就是官网给的案例了:

# models.py

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)

接下来可以这样求所有书籍的平均价格:

>>> from django.db.models import Avg, Max, Min

>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': Decimal('30.67')}

实际上可以省掉 all() :

>>> Book.objects.aggregate(Avg('price'))
{'price__avg': Decimal('30.67')}

还可以指定返回的键名:

>>> Book.objects.aggregate(price_avg=Avg('price'))
{'price_avg': Decimal('30.67')}

如果要获取所有书籍中的最高价格:

>>> Book.objects.aggregate(Max('price'))
{'price__max': Decimal('44')}

获取所有书籍中的最低价格:

>>> Book.objects.aggregate(Min('price'))
{'price__min': Decimal('12')}

aggregate() 方法返回的不再是 QuerySet 了,而是一个包含查询结果的字典。如果我要对 QerySet 中每个元素都进行聚合计算、并且返回的仍然是 QuerySet ,那就要用到 annotate() 方法了。

annotate 翻译过来就是 注解 ,它的作用有点像给 QuerySet 中的每个元素临时贴上一个临时的字段,字段的值是分组聚合运算的结果。

比方说要给查询集中的每本书籍都增加一个字段,字段内容是外链到书籍的作者的数量:

>>> from django.db.models import Count

>>> q = Book.objects.annotate(Count('authors'))
>>> q[0].authors__count
3

与 aggregate() 的语法类似,也可以给这个字段自定义个名字:

>>> q = Book.objects.annotate(a_count=Count('authors'))

跨外链查询字段也是可以的:

>>> s = Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))

>>> s[0].min_price
Decimal('12')
>>> s[0].max_price
Decimal('44')

既然 annotate() 返回的是查询集,那么自然也可以和 filter() 、 exclude() 等查询方法组合使用:

>>> b = Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))
>>> b[0].num_authors
4

联用的时候 filter 、 annotate 的顺序会影响返回结果,所以逻辑要想清楚。

也可以排序:

>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

总而言之, aggregate 和 annotate 用于组合查询。当你需要对某些字段进行聚合操作时(比如Sum, Avg, Max),请使用 aggregate 。如果你想要对数据集先进行分组(Group By)然后再进行某些聚合操作或排序时,请使用 annotate 。

进行此类查询有时候容易让人迷惑,如果你对查询的结果有任何的疑问,最好的方法就是直接查看它所执行的 SQL 原始语句,像这样:

>>> b = Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
>>> print(b.query)
SELECT "aggregation_book"."id", "aggregation_book"."name",
"aggregation_book"."pages", "aggregation_book"."price",
"aggregation_book"."rating", "aggregation_book"."publisher_id", 
"aggregation_book"."pubdate", COUNT("aggregation_book_authors"."author_id") 
AS "num_authors" FROM "aggregation_book" LEFT OUTER JOIN "aggregation_book_authors" 
ON ("aggregation_book"."id" = "aggregation_book_authors"."book_id") 
GROUP BY "aggregation_book"."id", "aggregation_book"."name",
"aggregation_book"."pages", "aggregation_book"."price",
"aggregation_book"."rating", "aggregation_book"."publisher_id", 
"aggregation_book"."pubdate"
ORDER BY "num_authors" ASC

相关文档: Aggregation

复合使用聚合时的相互干扰问题: Count and Sum annotations interfere with each other

总结

到此这篇关于Django中Aggregation聚合的基本使用方法就介绍到这了,更多相关Django Aggregation聚合使用内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python处理json数据中的中文
Mar 06 Python
Python使用修饰器执行函数的参数检查功能示例
Sep 26 Python
Python cookbook(数据结构与算法)从任意长度的可迭代对象中分解元素操作示例
Feb 13 Python
在cmd中运行.py文件: python的操作步骤
May 12 Python
python并发和异步编程实例
Nov 15 Python
pymongo中group by的操作方法教程
Mar 22 Python
Python内存管理实例分析
Jul 10 Python
python中hasattr()、getattr()、setattr()函数的使用
Aug 16 Python
感知器基础原理及python实现过程详解
Sep 30 Python
Python基于当前时间批量创建文件
May 07 Python
Python如何在main中调用函数内的函数方式
Jun 01 Python
python语言实现贪吃蛇游戏
Nov 13 Python
Python  word实现读取及导出代码解析
Jul 09 #Python
推荐技术人员一款Python开源库(造数据神器)
Jul 08 #Python
实例讲解Python 迭代器与生成器
Jul 08 #Python
opencv 阈值分割的具体使用
Jul 08 #Python
如何表示python中的相对路径
Jul 08 #Python
如何卸载python插件
Jul 08 #Python
python中数字是否为可变类型
Jul 08 #Python
You might like
深入理解PHP的远程多会话调试
2017/09/21 PHP
ThinkPHP5.0 图片上传生成缩略图实例代码说明
2018/06/20 PHP
PHP Include文件实例讲解
2019/02/15 PHP
JavaScript中null与undefined分析
2009/07/25 Javascript
javascript 数组排序函数
2009/08/20 Javascript
jQuery判断checkbox(复选框)是否被选中以及全选、反选实现代码
2014/02/21 Javascript
javascript自定义的addClass()方法
2014/05/28 Javascript
jquery原理以及学习技巧介绍
2015/11/11 Javascript
jQuery插件formValidator自定义函数扩展功能实例详解
2015/11/25 Javascript
JavaScript表单焦点自动切换代码
2016/07/24 Javascript
JS中使用FormData上传文件、图片的方法
2016/08/07 Javascript
总结十个Angular.js由浅入深的面试问题
2016/08/26 Javascript
js转html实体的方法
2016/09/27 Javascript
浅谈layer的iframe弹窗给里面的标签赋值的问题
2016/11/10 Javascript
jQuery实现动态文字搜索功能
2017/01/05 Javascript
JavaScript结合HTML DOM实现联动菜单
2017/04/05 Javascript
理解 javascript 中的函数表达式与函数声明
2017/07/07 Javascript
ajax+node+request爬取网络图片的实例(宅男福利)
2017/08/28 Javascript
JS返回页面时自动回滚到历史浏览位置
2018/09/26 Javascript
Nodejs实现用户注册功能
2019/04/14 NodeJs
微信小程序框架的页面布局代码
2019/08/17 Javascript
vue中使用router全局守卫实现页面拦截的示例
2020/10/23 Javascript
微信小程序实现倒计时功能
2020/11/19 Javascript
[01:07:19]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第一场 1月19日
2021/03/11 DOTA
python解决字符串倒序输出的问题
2018/06/25 Python
Python3爬虫使用Fidder实现APP爬取示例
2018/11/27 Python
提供世界各地便宜的机票:Sky-tours
2016/07/21 全球购物
美国快时尚彩妆品牌:Winky Lux(透明花瓣润唇膏)
2018/11/06 全球购物
大学毕业生简单自荐信
2013/11/05 职场文书
办护照工作证明范本
2014/01/14 职场文书
水果连锁超市创业计划书
2014/01/24 职场文书
求职信的最佳写作思路
2014/02/01 职场文书
国庆节演讲稿
2014/05/27 职场文书
开展创先争优活动总结
2014/08/28 职场文书
法人委托书的范本格式
2014/09/11 职场文书
基于Redis实现分布式锁的方法(lua脚本版)
2021/05/12 Redis