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版
Dec 07 Python
全面了解python字符串和字典
Jul 07 Python
Pycharm远程调试openstack的方法
Nov 21 Python
对Python实现简单的API接口实例讲解
Dec 10 Python
Python实现的爬取小说爬虫功能示例
Mar 30 Python
Django框架视图层URL映射与反向解析实例分析
Jul 29 Python
python使用socket 先读取长度,在读取报文内容示例
Sep 26 Python
使用Python生成200个激活码的实现方法
Nov 22 Python
python 字典访问的三种方法小结
Dec 05 Python
Python2和Python3中@abstractmethod使用方法
Feb 04 Python
Python如何将装饰器定义为类
Jul 30 Python
Python还能这么玩之只用30行代码从excel提取个人值班表
Jun 05 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链表操作简单示例
2016/10/15 PHP
浅谈PHP命令执行php文件需要注意的问题
2016/12/16 PHP
js对象与打印对象分析比较
2013/04/23 Javascript
JS写的贪吃蛇游戏(个人练习)
2013/07/08 Javascript
解析JavaScript中instanceof对于不同的构造器或许都返回true
2013/12/03 Javascript
js中实现多态采用和继承类似的方法
2014/08/22 Javascript
IE下支持文本框和密码框placeholder效果的JQuery插件分享
2015/01/31 Javascript
提升jQuery的性能需要做好七件事
2016/01/11 Javascript
JavaScript对象创建模式实例汇总
2016/10/03 Javascript
WEB前端实现裁剪上传图片功能
2016/10/17 Javascript
jQuery自定义组件(导入组件)
2016/11/08 Javascript
jstree的简单实例
2016/12/01 Javascript
JS前端笔试题分析
2016/12/19 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
Vue学习笔记进阶篇之单元素过度
2017/07/19 Javascript
jQuery+HTML5实现WebGL高性能烟花绽放动画效果【附demo源码下载】
2017/08/18 jQuery
浅谈NodeJs之数据库异常处理
2017/10/25 NodeJs
node简单实现一个更改头像功能的示例
2017/12/29 Javascript
element form 校验数组每一项实例代码
2019/10/10 Javascript
Python简单实现阿拉伯数字和罗马数字的互相转换功能示例
2018/04/17 Python
Python可变参数*args和**kwargs用法实例小结
2018/04/27 Python
Centos7 下安装最新的python3.8
2019/10/28 Python
python实现word文档批量转成自定义格式的excel文档的思路及实例代码
2020/02/21 Python
Python importlib模块重载使用方法详解
2020/10/13 Python
python使用yaml 管理selenium元素的示例
2020/12/01 Python
html5利用canvas实现颜色容差抠图功能
2019/12/23 HTML / CSS
餐厅楼面部长岗位职责范文
2014/02/16 职场文书
2014年圣诞节促销方案
2014/03/14 职场文书
2014年师德师风工作总结
2014/11/25 职场文书
2015年学校团委工作总结
2015/05/26 职场文书
婚庆开业庆典主持词
2015/06/30 职场文书
预备党员入党思想汇报(范文)
2019/08/14 职场文书
MySQL EXPLAIN输出列的详细解释
2021/05/12 MySQL
JPA如何使用entityManager执行SQL并指定返回类型
2021/06/15 Java/Android
MySQL 外键约束和表关系相关总结
2021/06/20 MySQL
什么是clearfix (一文搞清楚css清除浮动clearfix)
2023/05/21 HTML / CSS