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的Django框架的运行方式及处理流程
Apr 08 Python
Python实现将一个正整数分解质因数的方法分析
Dec 14 Python
Python 通过调用接口获取公交信息的实例
Dec 17 Python
python定时检测无响应进程并重启的实例代码
Apr 22 Python
详解爬虫被封的问题
Apr 23 Python
一行Python代码过滤标点符号等特殊字符
Aug 12 Python
Pytorch 使用CNN图像分类的实现
Jun 16 Python
Python虚拟环境库virtualenvwrapper安装及使用
Jun 17 Python
python的pip有什么用
Jun 17 Python
Django实现文章详情页面跳转代码实例
Sep 16 Python
5款实用的python 工具推荐
Oct 13 Python
Python基础之元类详解
Apr 29 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
PHP setcookie指定domain参数后,在IE下设置cookie失效的解决方法
2011/09/09 PHP
thinkPHP和onethink微信支付插件分享
2019/08/11 PHP
Laravel框架实现文件上传的方法分析
2019/09/29 PHP
新浪中用来显示flash的函数
2007/04/02 Javascript
FormValidate 表单验证功能代码更新并提供下载
2008/08/23 Javascript
网易JS面试题与Javascript词法作用域说明
2010/11/09 Javascript
IE6下focus与blur错乱的解决方案
2011/07/31 Javascript
javascript Event对象详解及使用示例
2013/11/22 Javascript
编写高质量JavaScript代码的基本要点
2016/03/02 Javascript
Bootstrap3学习笔记(三)之表格
2016/05/20 Javascript
jQuery Easyui datagrid/treegrid 清空数据
2016/07/09 Javascript
jQuery实现淡入淡出的模态框
2017/02/09 Javascript
jQuery扇形定时器插件pietimer使用方法详解
2017/07/18 jQuery
JavaScript数组排序reverse()和sort()方法详解
2017/12/24 Javascript
前端MVVM框架解析之双向绑定
2018/01/24 Javascript
JQuery选中select组件被选中的值方法
2018/03/08 jQuery
Nodejs异步回调之异常处理实例分析
2018/06/22 NodeJs
layui table数据修改的回显方法
2019/09/04 Javascript
H5 js点击按钮复制文本到粘贴板
2020/11/19 Javascript
[58:11]守擂赛第二周擂主赛 DeMonsTer vs Leopard
2020/04/28 DOTA
使用Python的Scrapy框架编写web爬虫的简单示例
2015/04/17 Python
Python中使用装饰器来优化尾递归的示例
2016/06/18 Python
django之session与分页(实例讲解)
2017/11/13 Python
对python中的six.moves模块的下载函数urlretrieve详解
2018/12/19 Python
Python字典循环添加一键多值的用法实例
2019/01/20 Python
Python列表的切片实例讲解
2019/08/20 Python
python实现梯度法 python最速下降法
2020/03/24 Python
Pycharm github配置实现过程图解
2020/10/13 Python
英国拳击装备购物网站:RDX Sports
2018/01/23 全球购物
普天C++笔试题
2016/03/20 面试题
常用UNIX 命令(Linux的常用命令)
2013/07/10 面试题
教师推荐信范文
2013/11/24 职场文书
超市重阳节活动方案
2014/02/10 职场文书
解决vue中provide inject的响应式监听
2022/04/19 Vue.js
Golang入门之计时器
2022/05/04 Golang