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 基础学习教程
Feb 08 Python
python实现博客文章爬虫示例
Feb 26 Python
Python实现的HTTP并发测试完整示例
Apr 23 Python
python用模块zlib压缩与解压字符串和文件的方法
Dec 16 Python
python监控键盘输入实例代码
Feb 09 Python
python中文编码与json中文输出问题详解
Aug 24 Python
解决python3中cv2读取中文路径的问题
Dec 05 Python
Python Django2.0集成Celery4.1教程
Nov 19 Python
Python日志器使用方法及原理解析
Sep 27 Python
Ubuntu16安装Python3.9的实现步骤
Dec 15 Python
python自动化发送邮件实例讲解
Jan 04 Python
Python Selenium破解滑块验证码最新版(GEETEST95%以上通过率)
Jan 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生成静态HTML速度快类库
2007/03/18 PHP
php获得当前的脚本网址
2007/12/10 PHP
基于empty函数的判断详解
2013/06/17 PHP
php实现监控varnish缓存服务器的状态
2014/12/30 PHP
通过代码实例解析PHP session工作原理
2020/12/11 PHP
21个值得收藏的Javascript技巧
2014/02/04 Javascript
JS定义类的六种方式详解
2016/05/12 Javascript
封装的dialog插件 基于bootstrap模态对话框的简单扩展
2016/08/10 Javascript
jQuey将序列化对象在前台显示地实现代码(方法总结)
2016/12/13 Javascript
js实现复选框的全选和取消全选效果
2017/01/03 Javascript
Javascript设计模式之装饰者模式详解篇
2017/01/17 Javascript
jquery将标签元素的高设为屏幕的百分比
2017/04/19 jQuery
Angular中的interceptors拦截器
2017/06/25 Javascript
使用Vue做一个简单的todo应用的三种方式的示例代码
2018/10/20 Javascript
解决Echarts2竖直datazoom滑动后显示数据不全的问题
2020/07/20 Javascript
JavaScript实现简单日历效果
2020/09/11 Javascript
import的本质解析
2017/10/30 Python
PyQt5实现拖放功能
2018/04/25 Python
python+selenium实现自动化百度搜索关键词
2019/06/03 Python
Django之全局使用request.user.username的实例详解
2020/05/14 Python
HTML5中input输入框默认提示文字向左向右移动的示例代码
2020/09/10 HTML / CSS
英国最大的老式糖果店:A Quarter Of
2017/04/08 全球购物
英国手工布艺沙发在线购买:Sofas & Stuff
2018/03/02 全球购物
Yahoo-PHP面试题4
2012/05/05 面试题
档案管理员岗位职责
2013/12/01 职场文书
毕业生自荐信如何写
2014/03/24 职场文书
党员批评与自我批评思想汇报
2014/10/08 职场文书
合同权益转让协议书模板
2014/11/18 职场文书
大学生逃课检讨书
2015/05/04 职场文书
党支部意见范文
2015/06/02 职场文书
导游词之安徽九华山
2019/09/18 职场文书
CSS3通过var()和calc()函数实现动画特效
2021/03/30 HTML / CSS
python实现简单倒计时功能
2021/04/21 Python
使用vue判断当前环境是安卓还是IOS
2022/04/12 Vue.js
Apache Hudi 加速传统的批处理模式
2022/04/24 Servers
Apache SkyWalking 监控 MySQL Server 实战解析
2022/09/23 Servers