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网络编程学习笔记(四):域名系统
Jun 09 Python
Python的Django框架使用入门指引
Apr 15 Python
python3+PyQt5+Qt Designer实现堆叠窗口部件
Apr 20 Python
dataframe 按条件替换某一列中的值方法
Jan 29 Python
Django中信号signals的简单使用方法
Jul 04 Python
pytorch中的卷积和池化计算方式详解
Jan 03 Python
Keras - GPU ID 和显存占用设定步骤
Jun 22 Python
vscode调试django项目的方法
Aug 06 Python
Django缓存Cache使用详解
Nov 30 Python
教你使用Python pypinyin库实现汉字转拼音
May 27 Python
Python 可迭代对象 iterable的具体使用
Aug 07 Python
梳理总结Python开发中需要摒弃的18个坏习惯
Jan 22 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 magic_quotes_gpc的一点认识与分析
2008/08/18 PHP
PHP性能优化准备篇图解PEAR安装
2011/12/05 PHP
YII Framework教程之异常处理详解
2016/03/14 PHP
PHP编程实现计算抽奖概率算法完整实例
2017/08/09 PHP
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
关于flash遮盖div浮动层的解决方法
2010/07/17 Javascript
提交表单时执行func方法实现代码
2013/03/17 Javascript
JavaScript实现函数返回多个值的方法
2015/06/09 Javascript
JavaScript中setFullYear()方法的使用详解
2015/06/11 Javascript
超实用的javascript时间处理总结
2016/08/16 Javascript
js动态生成form 并用ajax方式提交的实现方法
2016/09/09 Javascript
将JSON字符串转换成Map对象的方法
2016/11/30 Javascript
学习 NodeJS 第八天:Socket 通讯实例
2016/12/21 NodeJs
node.js基于mongodb的搜索分页示例
2017/01/22 Javascript
基于Vue实现支持按周切换的日历
2020/09/24 Javascript
利用Decorator如何控制Koa路由详解
2018/06/26 Javascript
基于element-ui组件手动实现单选和上传功能
2018/12/06 Javascript
微信小程序canvas截取任意形状的实现代码
2020/01/13 Javascript
vue使用axios实现excel文件下载的功能
2020/07/16 Javascript
[04:48]DOTA2亚洲邀请赛林书豪为VGJ加油
2017/04/01 DOTA
Python与R语言的简要对比
2017/11/14 Python
python实现决策树分类算法
2017/12/21 Python
浅谈Python使用Bottle来提供一个简单的web服务
2017/12/27 Python
python实现定时自动备份文件到其他主机的实例代码
2018/02/23 Python
python 解决动态的定义变量名,并给其赋值的方法(大数据处理)
2018/11/10 Python
python实现浪漫的烟花秀
2019/01/30 Python
Win10下Python3.7.3安装教程图解
2019/07/08 Python
Python 面向对象静态方法、类方法、属性方法知识点小结
2020/03/09 Python
Python字典实现伪切片功能
2020/10/28 Python
python之openpyxl模块的安装和基本用法(excel管理)
2021/02/03 Python
python自动生成sql语句的脚本
2021/02/24 Python
世界最大的私人旅行指南出版商:孤独星球
2016/08/23 全球购物
美国高端牛仔品牌:Silver Jeans
2019/12/12 全球购物
见习期自我鉴定
2014/01/31 职场文书
购房意向书
2014/08/30 职场文书
bose降噪耳机音能消除人声吗
2022/04/19 数码科技