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分割和拼接字符串
Nov 01 Python
用python + openpyxl处理excel2007文档思路以及心得
Jul 14 Python
两个命令把 Vim 打造成 Python IDE的方法
Mar 20 Python
python放大图片和画方格实现算法
Mar 30 Python
对python数据切割归并算法的实例讲解
Dec 12 Python
python selenium 查找隐藏元素 自动播放视频功能
Jul 24 Python
python线程安全及多进程多线程实现方法详解
Sep 27 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
Nov 11 Python
在OpenCV里使用Camshift算法的实现
Nov 22 Python
解决启动django,浏览器显示“服务器拒绝访问”的问题
May 13 Python
Python爬虫+Tkinter制作一个翻译软件的示例
Feb 20 Python
使用tensorflow 实现反向传播求导
May 26 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
apache2.2.4+mysql5.0.77+php5.2.8安装精简
2009/04/29 PHP
PHPMailer 中文使用说明小结
2010/01/22 PHP
PHP 类相关函数的使用详解
2013/05/10 PHP
使用array_map简单搞定PHP删除文件、删除目录
2014/10/29 PHP
JavaScript 继承使用分析
2011/05/12 Javascript
javascript 弹出层组件(升级版)
2011/05/12 Javascript
javascript定义变量时有var和没有var的区别探讨
2014/07/21 Javascript
js实现TAB切换对应不同颜色的代码
2015/08/31 Javascript
jQuery中slidedown与slideup方法用法示例
2016/09/16 Javascript
关于js二维数组和多维数组的定义声明(详解)
2016/10/02 Javascript
微信小程序实战之运维小项目
2017/01/17 Javascript
利用javascript如何随机生成一定位数的密码
2017/09/22 Javascript
js构造函数创建对象是否加new问题
2018/01/22 Javascript
vue中多路由表头吸顶实现的几种布局方式
2019/04/12 Javascript
JS实现的简单tab切换功能完整示例
2019/06/20 Javascript
[00:32]2018DOTA2亚洲邀请赛Newbee出场
2018/04/03 DOTA
详解python中 os._exit() 和 sys.exit(), exit(0)和exit(1) 的用法和区别
2017/06/23 Python
Python利用BeautifulSoup解析Html的方法示例
2017/07/30 Python
详解Python使用tensorflow入门指南
2018/02/09 Python
python子线程退出及线程退出控制的代码
2019/10/16 Python
Python input函数使用实例解析
2019/11/22 Python
Pycharm最常用的快捷键及使用技巧
2020/03/05 Python
离线状态下在jupyter notebook中使用plotly实例
2020/04/24 Python
CSS3的Flexbox布局的简明入门指南
2016/04/08 HTML / CSS
Gtech官方网站:地毯清洁器、吸尘器及园艺设备
2018/05/23 全球购物
都柏林通行卡/城市通票:The Dublin Pass
2020/02/16 全球购物
学子宴答谢词
2014/01/25 职场文书
成绩单公证书
2014/04/10 职场文书
企业仓管员岗位职责
2014/06/15 职场文书
党在我心中演讲稿
2014/09/02 职场文书
史上最牛辞职信
2015/05/13 职场文书
初婚未育证明样本
2015/06/18 职场文书
靠谱的活动总结
2019/04/16 职场文书
3招让你摆脱即兴讲话冷场尴尬
2019/08/08 职场文书
Element实现动态表格的示例代码
2021/08/02 Javascript
设置IIS Express并发数
2022/07/07 Servers