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实现批量重命名文件的代码
May 25 Python
介绍Python中的__future__模块
Apr 27 Python
Python3遍历目录树实现方法
May 22 Python
django ajax json的实例代码
May 29 Python
python 字典修改键(key)的几种方法
Aug 10 Python
用Python和WordCloud绘制词云的实现方法(内附让字体清晰的秘笈)
Jan 08 Python
Python selenium模拟手动操作实现无人值守刷积分功能
May 13 Python
python中rb含义理解
Jun 18 Python
想学画画?python满足你!
Dec 24 Python
Python爬虫之爬取二手房信息
Apr 27 Python
Pytorch中Softmax与LogSigmoid的对比分析
Jun 05 Python
再谈python_tkinter弹出对话框创建
Mar 20 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取得一个类的属性和方法的实现代码
2011/05/22 PHP
提高PHP性能的编码技巧以及性能优化详细解析
2013/08/24 PHP
php中print(),print_r(),echo()的区别详解
2014/12/01 PHP
Yii框架调试心得--在页面输出执行sql语句
2014/12/25 PHP
php计算给定时间之前的函数用法实例
2015/04/03 PHP
PHP类和对象相关系统函数与运算符小结
2016/09/28 PHP
thinkPHP5框架自定义验证器实现方法分析
2018/06/11 PHP
php实现有序数组旋转后寻找最小值方法
2018/09/27 PHP
javascript读取xml
2006/11/04 Javascript
解决使用attachEvent函数时,this指向被绑定的元素的问题的方法
2007/08/13 Javascript
javascript 数组学习资料收集
2010/04/11 Javascript
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
jQuery Ajax和getJSON获取后台普通json数据和层级json数据用法分析
2016/06/08 Javascript
高效Web开发的10个jQuery代码片段
2016/07/22 Javascript
js实现键盘自动打字效果
2016/12/23 Javascript
javascript实现简单的ajax封装示例
2016/12/28 Javascript
详解Angualr 组件间通信
2017/01/21 Javascript
使用vue-router为每个路由配置各自的title
2018/07/30 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
vue 实现移动端键盘搜索事件监听
2019/11/06 Javascript
[06:14]《辉夜杯》外卡赛附加赛 4支战队巡礼
2015/10/23 DOTA
10个易被忽视但应掌握的Python基本用法
2015/04/01 Python
Python实现Windows上气泡提醒效果的方法
2015/06/03 Python
Python实现将数据库一键导出为Excel表格的实例
2016/12/30 Python
Django模板变量如何传递给外部js调用的方法小结
2017/07/24 Python
python实现Dijkstra静态寻路算法
2019/01/17 Python
下载官网python并安装的步骤详解
2019/10/12 Python
基于python的docx模块处理word和WPS的docx格式文件方式
2020/02/13 Python
Notino瑞典:购买香水和美容产品
2019/07/26 全球购物
泰国Robinson百货官网:购买知名品牌的商品
2020/02/08 全球购物
九年级英语教学反思
2014/01/31 职场文书
医科大学毕业生自荐信
2014/02/03 职场文书
卫生院健康教育实施方案
2014/06/07 职场文书
杭州西湖英语导游词
2015/02/03 职场文书
Python安装使用Scrapy框架
2022/04/12 Python
利用Python脚本写端口扫描器socket,python-nmap
2022/07/23 Python