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中random模块用法实例分析
May 19 Python
python读写ini配置文件方法实例分析
Jun 30 Python
Windows下Python使用Pandas模块操作Excel文件的教程
May 31 Python
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
Dec 27 Python
Python实现字典按照value进行排序的方法分析
Dec 23 Python
django解决跨域请求的问题
Nov 11 Python
python pyinstaller 加载ui路径方法
Jun 10 Python
PyCharm 创建指定版本的 Django(超详图解教程)
Jun 18 Python
Pandas之Dropna滤除缺失数据的实现方法
Jun 25 Python
python 对任意数据和曲线进行拟合并求出函数表达式的三种解决方案
Feb 18 Python
Python 实现平台类游戏添加跳跃功能
Mar 27 Python
python自动打开浏览器下载zip并提取内容写入excel
Jan 04 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作的文本留言本的例子(五)
2006/10/09 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
PHP远程连接oracle数据库操作实现方法图文详解
2019/04/11 PHP
VSCode+PHPstudy配置PHP开发环境的步骤详解
2020/08/20 PHP
javascript jQuery插件练习
2008/12/24 Javascript
JavaScript的parseInt 进制问题
2009/05/07 Javascript
angular分页指令操作
2017/01/09 Javascript
jQuery插件zTree实现删除树子节点的方法示例
2017/03/08 Javascript
如何在 Vue.js 中使用第三方js库
2017/04/25 Javascript
微信小程序 request接口的封装实例代码
2017/04/26 Javascript
利用canvas实现的加载动画效果实例代码
2017/07/05 Javascript
前端跨域的几种解决方式总结(推荐)
2017/08/16 Javascript
javascript关于“时间”的一次探索
2019/07/24 Javascript
在vue中动态添加class类进行显示隐藏实例
2019/11/09 Javascript
[36:29]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs TNC
2018/04/02 DOTA
Python类定义和类继承详解
2015/05/08 Python
Python实现获取域名所用服务器的真实IP
2015/10/25 Python
详解Python3中字符串中的数字提取方法
2017/01/14 Python
Pyqt实现无边框窗口拖动以及窗口大小改变
2018/04/19 Python
Python图像处理PIL各模块详细介绍(推荐)
2019/07/17 Python
解析Python 偏函数用法全方位实现
2020/06/26 Python
如何用Anaconda搭建虚拟环境并创建Django项目
2020/08/02 Python
使用CSS3滤镜的filter:blur属性制作毛玻璃模糊效果的方法
2016/07/08 HTML / CSS
岗位职责的含义
2013/11/17 职场文书
外贸采购员求职的自我评价
2013/11/26 职场文书
物流仓管员岗位职责
2013/12/04 职场文书
ktv收银员岗位职责
2013/12/16 职场文书
设计大赛策划方案
2014/06/13 职场文书
贯彻落实“八项规定”思想汇报
2014/09/13 职场文书
县政府领导班子“四风”方面突出问题整改措施
2014/09/23 职场文书
旷课检讨书
2015/01/26 职场文书
关于教师节的广播稿
2015/08/19 职场文书
2016思想纪律作风整顿心得体会
2016/01/23 职场文书
《我是什么》教学反思
2016/02/16 职场文书
详解CocosCreator消息分发机制
2021/04/16 Javascript
JavaScript实现显示和隐藏图片
2021/04/29 Javascript