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 11 Python
Python中最常用的操作列表的几种方法归纳
Apr 24 Python
用Python操作字符串之rindex()方法的使用
May 19 Python
python实现八大排序算法(1)
Sep 14 Python
python的socket编程入门
Jan 29 Python
如何实现删除numpy.array中的行或列
May 08 Python
Python实现 版本号对比功能的实例代码
Apr 18 Python
Python Flask框架扩展操作示例
May 03 Python
python实现身份证实名认证的方法实例
Nov 08 Python
python 通过邮件控制实现远程控制电脑操作
Mar 16 Python
怎么解决pycharm license Acti的方法
Oct 28 Python
PyChon中关于Jekins的详细安装(推荐)
Dec 28 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数据库连接类~~做成一个分页类!
2006/11/25 PHP
php cookie 作用范围?不要在当前页面使用你的cookie
2009/03/24 PHP
php UBB 解析实现代码
2011/11/27 PHP
PHP中include与require使用方法区别详解
2013/10/19 PHP
PHP中通过fopen()函数访问远程文件示例
2014/11/18 PHP
php生成圆角图片的方法
2015/04/07 PHP
Symfony2在Nginx下的配置方法图文教程
2016/02/04 PHP
PHP实现动态添加XML中数据的方法
2018/03/30 PHP
PHP的curl函数的用法总结
2019/02/14 PHP
List Information About the Binary Files Used by an Application
2007/06/18 Javascript
基于JQuery实现CheckBox全选全不选
2011/06/27 Javascript
setTimeout()递归调用不加引号出错的解决方法
2014/09/05 Javascript
jquery制作多功能轮播图插件
2015/04/02 Javascript
简介JavaScript中search()方法的使用
2015/06/06 Javascript
AngularJS表单和输入验证实例
2016/11/02 Javascript
JS实现颜色动态淡化效果
2017/03/06 Javascript
如何理解Vue的v-model指令的使用方法
2018/07/19 Javascript
Vue动态加载异步组件的方法
2018/11/21 Javascript
使用Layui搭建后台管理界面的操作方法
2019/09/20 Javascript
JavaScript常用工具函数汇总(浏览器环境)
2020/09/17 Javascript
[00:09]DOTA2全国高校联赛 精彩活动引爆全场
2018/05/30 DOTA
Python中的with语句与上下文管理器学习总结
2016/06/28 Python
Scrapy的简单使用教程
2017/10/24 Python
Python大数据之网络爬虫的post请求、get请求区别实例分析
2019/11/16 Python
python如何实现不可变字典inmutabledict
2020/01/08 Python
台湾最大网路书店:博客来
2018/03/18 全球购物
KOHLER科勒美国官网:国际著名卫浴橱柜领先品牌
2020/06/27 全球购物
2019年分享net面试的经历和题目
2016/08/07 面试题
大学本科毕业生的自我鉴定
2013/11/26 职场文书
前台接待岗位职责
2013/12/03 职场文书
毕业生个人求职信范例分享
2013/12/17 职场文书
岗位职责风险点
2014/03/12 职场文书
活动总结新闻稿
2014/08/30 职场文书
工人先锋号申报材料
2014/12/29 职场文书
高中生军训感言
2015/08/01 职场文书
MySQL表字段数量限制及行大小限制详情
2022/07/23 MySQL