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进阶教程之动态类型详解
Aug 30 Python
python搜索指定目录的方法
Apr 29 Python
Python中处理字符串之isalpha()方法的使用
May 18 Python
Python 2与Python 3版本和编码的对比
Feb 14 Python
Python_LDA实现方法详解
Oct 25 Python
对python 多线程中的守护线程与join的用法详解
Feb 18 Python
Python (Win)readline和tab补全的安装方法
Aug 27 Python
利用Python产生加密表和解密表的实现方法
Oct 15 Python
python如何实现单链表的反转
Feb 10 Python
pytorch实现CNN卷积神经网络
Feb 19 Python
Python开发入门——迭代的基本使用
Sep 03 Python
Matlab如何实现矩阵复制扩充
Jun 02 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/12/06 PHP
php Undefined index的问题
2009/06/01 PHP
PHP错误提示的关闭方法详解
2013/06/23 PHP
PHP curl 获取响应的状态码的方法
2014/01/13 PHP
php实现将任意进制数转换成10进制的方法
2015/04/17 PHP
php如何实现只替换一次或N次
2015/10/29 PHP
33种Javascript 表格排序控件收集
2009/12/03 Javascript
15 个 JavaScript Web UI 库
2010/05/19 Javascript
javascript中强制执行toString()具体实现
2013/04/27 Javascript
jquery 取子节点及当前节点属性值的方法
2014/08/24 Javascript
JavaScript省市区三级联动菜单效果
2016/09/21 Javascript
jQuery中DOM节点删除之empty与remove
2017/01/20 Javascript
原生JS实现左右箭头选择日期实例代码
2017/03/14 Javascript
详解使用angularjs的ng-options时如何设置默认值(初始值)
2017/07/18 Javascript
express框架实现基于Websocket建立的简易聊天室
2017/08/10 Javascript
动态Axios的配置步骤详解
2018/01/12 Javascript
webpack-dev-server自动更新页面方法
2018/02/22 Javascript
修改npm全局安装模式的路径方法
2018/05/15 Javascript
解决vue 格式化银行卡(信用卡)每4位一个符号隔断的问题
2018/09/14 Javascript
vue-router实现嵌套路由的讲解
2019/01/19 Javascript
elementUI Tree 树形控件的官方使用文档
2019/04/25 Javascript
vue之a-table中实现清空选中的数据
2019/11/07 Javascript
JS forEach跳出循环2种实现方法
2020/06/24 Javascript
[05:08]顺网杯ISS-DOTA2赛歌 少女偶像Lunar青春演绎
2013/12/05 DOTA
python中sleep函数用法实例分析
2015/04/29 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
2017/08/18 Python
Flask框架工厂函数用法实例分析
2019/05/25 Python
手写一个python迭代器过程详解
2019/08/27 Python
完美解决jupyter由于无法import新包的问题
2020/05/26 Python
纯CSS实现预加载动画效果
2017/09/06 HTML / CSS
施华洛世奇新加坡官网:SWAROVSKI新加坡
2020/10/06 全球购物
网络工程专业自荐信范文
2014/03/16 职场文书
《二泉映月》教学反思
2014/04/15 职场文书
公司年会策划方案
2014/05/17 职场文书
Python OpenCV形态学运算示例详解
2022/04/07 Python
输入框跟随文字内容适配宽实现示例
2022/08/14 Javascript