Django中Aggregation聚合的基本使用方法
作者:lunarian 发布时间:2023-09-15 02:38:29
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
来源:https://segmentfault.com/a/1190000023097440


猜你喜欢
- 网上的SQL优化的文章实在是很多,说实在的,我也曾经到处找这样的文章,什么不要使用IN了,什么OR了,什么AND了,很多很多,还有很多人拿出
- 目录1. 画布(canvas) 1.1 设置画布大小2. 画笔 2.1 画笔的状态 2.2 画笔的属性 2.3 绘图命令3. 命令详
- 一、类型转换 1.转换成字串 ECMAScript的Boolean值、数字和字串的原始值的有趣之处在于它们是伪对象,这意味着它们实际上具有属
- 本文实例为大家分享了Python3 Tkinkter + SQLite 实现登录和注册界面,供大家参考,具体内容如下Ubuntu14 + P
- 下面是例子分析表A记录如下: aID aNum
- 约束的概念约束:通过限制用户操作的方式,来达到维护数据本身安全,完整性的一套方案。为什么要有约束? Mysql是一套整体的数据存储解决方案,
- 1、php支持哪些数据库(拥有哪些数据库接口)Adabas D ,InterBase ,PostgreSQL ,dBase ,FrontBa
- 情景描述在项目开发过程中,不同项目阶段可能会有不同的分支,当创建好一个分支后,就需要将代码切换到这个分支上进行代码同步,例如将当前 orig
- 本文实例讲述了python获取指定网页上所有超链接的方法。分享给大家供大家参考。具体如下:这段python代码通过urllib2抓取网页,然
- 在编写Web自动化测试用例的时候,如何写断言使新手不解,严格意义上来讲,没有断言的自动化脚本不能叫测试用例。就像功能测试一样,当测试人员做了
- 图形化验证码生成和验证功能介绍在使用用户名和密码登录功能时,需要填写验证码,验证码是以图形化的方式进行获取和展示的。验证码使用原理验证码的使
- 1.查询表名: 代码如下:select table_name,tablespace_name,temporary from user_tab
- 不管是在信贷领域还是支付领域,作为一个风控人员,我们都需要对部署的策略模型进行监控,信贷领域可能还需要对客户的逾期表现进行监控。这时,如果我
- 常见的SQL问题:◆选择重复,消除重复和选择出序列有例表:empemp_no name age001 Tom 17002 Sun 14003
- 背景介绍Pandas的DataFrame和Series在Matplotlib基础上封装了一个简易的绘图函数,使得数据处理过程中方便可视化查看
- 前言:随着编程语言的发展,Go 还很年轻。它于 2009 年 11 月 10 日首次发布。其创建者Robert Griesemer Rob
- mysql drop database命令用于删除一个数据库,如果试图使用drop database命令删除一个不存在的数据库,那么那么你会
- import time, randomclass GuessNum: def __init__(self
- 一、使用loadVariables 一个例子简单的描述了如何通过GET方法向服务器端的ASP发送请求: _root. pushAc
- Symfony2是一个基于PHP语言的Web开发框架,有着开发速度快、性能高等特点。本文以一个程序示例的实现过程详细叙述了Symfony2框