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回调函数用法实例详解
Jul 02 Python
python代码实现ID3决策树算法
Dec 20 Python
Tensorflow 查看变量的值方法
Jun 14 Python
python获取服务器响应cookie的实例
Dec 28 Python
利用python Selenium实现自动登陆京东签到领金币功能
Oct 31 Python
python set集合使用方法解析
Nov 05 Python
Python打开文件、文件读写操作、with方式、文件常用函数实例分析
Jan 07 Python
Python django框架开发发布会签到系统(web开发)
Feb 12 Python
django 数据库 get_or_create函数返回值是tuple的问题
May 15 Python
Java Unsafe类实现原理及测试代码
Sep 15 Python
jupyter notebook保存文件默认路径更改方法汇总(亲测可以)
Jun 09 Python
Python中time与datetime模块使用方法详解
Mar 31 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通过字符串调用函数示例
2014/03/02 PHP
使用PHP生成二维码的两种方法(带logo图像)
2014/03/14 PHP
php reset() 函数指针指向数组中的第一个元素并输出实例代码
2016/11/21 PHP
php远程请求CURL实例教程(爬虫、保存登录状态)
2020/12/10 PHP
js动态生成指定行数的表格
2013/07/11 Javascript
asp.net+js实现金额格式化
2015/02/27 Javascript
Windows系统下使用Sublime搭建nodejs环境
2015/04/13 NodeJs
jQuery 如何给Carousel插件添加新的功能
2016/04/18 Javascript
js制作网站首页图片轮播特效代码
2016/08/30 Javascript
javascript十六进制数字和ASCII字符之间的转换方法
2016/12/27 Javascript
JavaScript原生节点操作小结
2017/01/17 Javascript
基于vue实现分页效果
2017/11/06 Javascript
官方推荐react-navigation的具体使用详解
2018/05/08 Javascript
nodeJs爬虫的技术点总结
2018/05/13 NodeJs
JS实现获取当前所在周的周六、周日示例分析
2019/05/11 Javascript
JS实现的简单tab切换功能完整示例
2019/06/20 Javascript
监控Nodejs的性能实例代码
2019/07/02 NodeJs
JS合并两个数组的3种方法详解
2019/10/24 Javascript
微信小程序如何实现radio单选框单击打勾和取消
2020/01/21 Javascript
用Angular实现一个扫雷的游戏示例
2020/05/15 Javascript
Python编写检测数据库SA用户的方法
2014/07/11 Python
初步解析Python中的yield函数的用法
2015/04/03 Python
浅析Python中signal包的使用
2015/11/13 Python
Python通过matplotlib绘制动画简单实例
2017/12/13 Python
Anaconda下配置python+opencv+contribx的实例讲解
2018/08/06 Python
Python3 关于pycharm自动导入包快捷设置的方法
2019/01/16 Python
python基础梳理(一)(推荐)
2019/04/06 Python
Pandas实现DataFrame按行求百分数(比例数)
2019/12/27 Python
应聘自荐信
2013/12/14 职场文书
先进德育工作者事迹材料
2014/01/24 职场文书
大学生旅游业创业计划书
2014/01/29 职场文书
汽车装潢店创业计划书范文
2014/02/05 职场文书
美国探亲签证邀请信
2014/02/05 职场文书
论语读书笔记
2015/06/26 职场文书
实践论读书笔记
2015/06/29 职场文书
求职信如何撰写?
2019/05/22 职场文书