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爬虫入门教程--HTML文本的解析库BeautifulSoup(四)
May 25 Python
Python爬虫抓取代理IP并检验可用性的实例
May 07 Python
pygame游戏之旅 如何制作游戏障碍
Nov 20 Python
Python实现的KMeans聚类算法实例分析
Dec 29 Python
python找出列表中大于某个阈值的数据段示例
Nov 24 Python
Python实现将蓝底照片转化为白底照片功能完整实例
Dec 13 Python
pytorch 实现cross entropy损失函数计算方式
Jan 02 Python
python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例
Feb 26 Python
keras自定义损失函数并且模型加载的写法介绍
Jun 15 Python
python爬虫中抓取指数的实例讲解
Dec 01 Python
python实现自动化群控的步骤
Apr 11 Python
如何使用Python实现一个简易的ORM模型
May 12 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
Sony CFR 320 修复改造
2020/03/14 无线电
php header功能的使用
2013/10/28 PHP
微信公众号开发之获取位置信息php代码
2018/06/13 PHP
CentOS7.0下安装PHP5.6.30服务的教程详解
2018/09/29 PHP
PHP实现二维数组按照指定的字段进行排序算法示例
2019/04/23 PHP
JavaScript 全角转半角部分
2009/10/28 Javascript
js 中 document.createEvent的用法
2010/08/29 Javascript
js+div实现图片滚动效果代码
2014/02/10 Javascript
jQuery添加删除DOM元素方法详解
2016/01/18 Javascript
基于JQuery实现图片轮播效果(焦点图)
2016/02/02 Javascript
基于jquery实现百度新闻导航菜单滑动动画
2016/03/15 Javascript
jQuery封装的屏幕居中提示信息代码
2016/06/08 Javascript
遍历json 对象的属性并且动态添加属性的实现
2016/12/02 Javascript
Vuex简单入门
2017/04/19 Javascript
Vue 2.5 Level E 发布了: 新功能特性一览
2017/10/24 Javascript
vue.js整合vux中的上拉加载下拉刷新实例教程
2018/01/09 Javascript
详解Vue单元测试Karma+Mocha学习笔记
2018/01/31 Javascript
解决微信小程序中转换时间格式IOS不兼容的问题
2019/02/15 Javascript
一次让你了解全部JavaScript的作用域
2019/06/24 Javascript
详解nuxt 微信公众号支付遇到的问题与解决
2019/08/26 Javascript
vue请求服务器数据后绑定不上的解决方法
2019/10/30 Javascript
vue实现的封装全局filter并统一管理操作示例
2020/02/02 Javascript
2020京东618叠蛋糕js脚本(亲测好用)
2020/06/02 Javascript
Javascript新手入门之字符串拼接与变量的应用
2020/12/03 Javascript
使用python编写批量卸载手机中安装的android应用脚本
2014/07/21 Python
对Python Pexpect 模块的使用说明详解
2019/02/14 Python
Django实现CAS+OAuth2的方法示例
2019/10/30 Python
python实现的多任务版udp聊天器功能案例
2019/11/13 Python
英国电动工具购买网站:Anglia Tool Centre
2017/04/25 全球购物
网络方面基础面试题
2012/11/16 面试题
本科生求职信
2014/06/17 职场文书
党的群众路线教育实践活动个人对照检查剖析材料
2014/09/23 职场文书
政府班子四风问题整改措施思想汇报
2014/10/08 职场文书
党员公开承诺书(2016最新版)
2016/03/24 职场文书
python实现简单倒计时功能
2021/04/21 Python
golang 实现对Map进行键值自定义排序
2021/04/28 Golang