aggregate和annotate使用
aggregate和annotate方法的使用场景
Django的aggregate和annotate方法属于高级查询方法,主要用于组合查询,是Django高手们必需要熟练掌握的。当我们需要对查询集(queryset)的某些字段进行计算或进行先分组再计算或排序, 我们就需要使用aggregate和annotate方法了。
假如我们有如下一个模型,其中Student与Hobby(爱好)是多对多的关系。我们想要知道所有学生的平均年龄,我们常规做法一般是利用for循环从数据库中把符合查询条件的student对象一个一个取出,把他们年龄相加,然后再除以总人数。当人数非常多而我们又只需要平均年龄这条信息时,把所有符合查询条件的学生对象都载入内存后再进行计算是非常浪费资源的,效率也非常低。一个更好的方法是在数据库层面提取查询数据时就直接返回我们所需要的信息。因为这个查询涉及到对整个queryset的age字段进行统计计算,此时django的聚合函数方法aggregate就可以帮我们大大提升查询效率了[见后文]。
class Student(models.Model): name = models.CharField(max_length=20)
age = models.IntegerField()
hobbies = models.ManyToManyField(Hobby) class Hobby(models.Model):
name = models.CharField(max_length=20)
另一个例子是统计最受学生欢迎的5个爱好,常规做法是先将所有hobby对象提取出来,载入内存。然后利用for循环统计每组爱好对应的学生人数,再构建一个新的查询集,按每组人数从大到小进行排序。这个查询需要根据hobby先进行分组,再统计每个爱好组里学生的数量,然后进行排序。对于这个复杂查询, django的annotate方法一句话就可以解决问题。
aggregate()方法详解
aggregate的中文意思是聚合, 源于SQL的聚合函数。Django的aggregate()方法作用是对一组值(比如queryset的某个字段)进行统计计算,并以字典(Dict)格式返回统计计算结果。django的aggregate方法支持的聚合操作有AVG / COUNT / MAX / MIN /SUM 等。
我们现在来看下几组实际使用案例。使用前别忘了import Avg, Max, Min或者Sum方法哦
from django.db.models import Avg, Max, Min
# 计算学生平均年龄, 返回字典。age和avg间是双下划线哦
Student.objects.all().aggregate(Avg('age'))
{ 'age__avg': 12 }
# 学生平均年龄,返回字典。all()不是必须的。
Student.objects.aggregate(Avg('age'))
{ 'age__avg: 12' }
# 计算学生总年龄, 返回字典。
Student.objects.aggregate(Sum('age'))
{ 'age__sum': 144 }
# 学生平均年龄, 设置字典的key
Student.objects.aggregate(average_age = Avg('age'))
{ 'average_age': 12 }
# 学生最大年龄,返回字典
Student.objects.aggregate(Max('age'))
{ 'age__max': 12 }
# 同时获取学生年龄均值, 最大值和最小值, 返回字典
Student.objects.aggregate(Avg('age‘), Max('age‘), Min('age‘))
{ 'age__avg': 12, 'age__max': 18, 'age__min': 6, }
# 根据Hobby反查学生最大年龄。查询字段student和age间有双下划线哦。
Hobby.objects.aggregate(Max('student__age'))
{ 'student__age__max': 12 }
你注意到了吗? aggregate方法返回Dict类型数据和django的内容对象(context object)是一样的哦。你可以很轻松地将结果传递给模板, 在模板中显示。
annotate()方法详解
annotate的中文意思是注释,小编我觉得是非常地词不达意,一个更好的理解是分组(Group By)。如果你想要对数据集先进行分组然后再进行某些聚合操作或排序时,需要使用annotate方法来实现。与aggregate方法不同的是,annotate方法返回结果的不仅仅是含有统计结果的一个字典,而是包含有新增统计字段的查询集(queryset).
我们接下来也看下几个实际使用案例。
# 按学生分组,统计每个学生的爱好数量
Student.objects.annotate(Count('hobbies'))
返回的结果依然是Student查询集,只不过多了hobbies__count这个字段。如果你不喜欢这个默认名字,你当然可以对这个字段进行自定义从而使它变得更直观。
# 按学生分组,统计每个学生爱好数量,并自定义字段名
Student.objects.annotate(hobby_count_by_student=Count('hobbies'))
# 按爱好分组,再统计每组学生数量。
Hobby.objects.annotate(Count('student'))
# 按爱好分组,再统计每组学生最大年龄。
Hobby.objects.annotate(Max('student__age'))
Annotate方法与Filter方法联用
有时我们需要先对数据集先筛选再分组,有时我们还需要先分组再对查询集进行筛选。根据需求不同,我们可以合理地联用annotate方法和filter方法。注意: annotate和filter方法联用时使用顺序很重要。
# 先按爱好分组,再统计每组学生数量, 然后筛选出学生数量大于1的爱好。
Hobby.objects.annotate(student_num=Count('student')).filter(student_num__gt=1)
# 先按爱好分组,筛选出以'd'开头的爱好,再统计每组学生数量。
Hobby.objects.filter(name__startswith="d").annotate(student_num=Count('student‘))
Annotate与order_by()联用
我们同样可以使用order_by方法对annotate方法返回的数据集进行排序。
# 先按爱好分组,再统计每组学生数量, 然后按每组学生数量大小对爱好排序。
Hobby.objects.annotate(student_num=Count('student‘)).order_by('student_num')
# 统计最受学生欢迎的5个爱好。
Hobby.objects.annotate(student_num=Count('student‘)).order_by('-student_num')[:5]
Annotate与values()联用
我们在前例中按学生对象进行分组,我们同样可以按学生姓名name来进行分组。唯一区别是本例中,如果两个学生具有相同名字,那么他们的爱好数量将叠加。
# 按学生名字分组,统计每个学生的爱好数量。
Student.objects.values('name').annotate(Count('hobbies'))
你还可以使用values方法从annotate返回的数据集里提取你所需要的字段,如下所示:
# 按学生名字分组,统计每个学生的爱好数量。
Student.objects.annotate(hobby_count=Count('hobbies')).values('name', 'hobby_count')
小结
Django的aggregate和annotate方法属于高级查询方法,主要用于组合查询,可以大大提升数据库查询效率。当你需要对查询集(queryset)的某些字段进行聚合操作时(比如Sum, Avg, Max),请使用aggregate方法。如果你想要对数据集先进行分组(Group By)然后再进行某些聚合操作或排序时,请使用annotate方法。
aggregate和annotate使用的更多相关文章
- django的聚合函数和aggregate、annotate方法使用
支持聚合函数的方法: 提到聚合函数,首先我们要知道的就是这些聚合函数是不能在django中单独使用的,要想在django中使用这些聚合函数,就必须把这些聚合函数放到支持他们的方法内去执行.支持聚合函数 ...
- aggregate和annotate方法使用详解与示例
aggregate和annotate方法的使用场景 Django的aggregate和annotate方法属于高级查询方法,主要用于组合查询.当我们需要对查询集(queryset)的某些字段进行计算或 ...
- [TimLinux] django aggregate和annotate示例
1. 聚合与注解 聚合(aggregate)比较好理解,注解(annotate)真不好理解,这篇示例参考了文章“django中聚合aggregate和annotate GROUP BY的使用方法”提供 ...
- 72.Python中ORM聚合函数详解:Avg,aggregate,annotate
聚合函数: 如果你用原生SQL语句,则可以使用聚合函数提取数据.比如提取某个商品销售的数量,那么就可以使用Count,如果想要知道销售的平均价格,那么就可以使用Avg. 聚合函数是通过aggregat ...
- Django的aggregate()和annotate()函数的区别
aggregate() aggregate()为所有的QuerySet生成一个汇总值,相当于Count().返回结果类型为Dict. annotate() annotate()为每一个QuerySet ...
- django中聚合aggregate和annotate GROUP BY的使用方法
接触django已经很长时间了,但是使用QuerySet查询集的方式一直比较低端,只会使用filter/Q函数/exclude等方式来查询,数据量比较小的时候还可以,但是如果数据量很大,而且查询比较复 ...
- Django ORM模型的一点体会
作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...
- Django 模型和数据库 总结
模型和数据库 模型 首先我们在创建一个model的时候,这个类都是继承自 django.db.models.Model, 各种Model Field类型 AutoField,自动增长的IntegerF ...
- Python数据库查询之组合条件查询-F&Q查询
F查询(取字段的值) 关于查询我们知道有filter( ) ,values( ) , get( ) ,exclude( ) ,如果是聚合分组,还会用到aggregate和annotate,甚至还有万能 ...
随机推荐
- 解决“每次启动Access2010时都要求配置VS2008”的办法
我每次启动Access2010时都会要求配置VS2008,这大概是VS2008与office(Access2010)有冲突引起的.这里提供一种解决办法. 依次选择Access2010的文件-选项中-加 ...
- [洛谷P2186] 小Z的栈函数
题目链接: 传送门 题目分析: 大模拟,先得存操作,然后再处理每个数-- 有一个小优化,在处理操作的时候顺便判一下最后栈里是不是有且仅有一个数,但A完了才想起来,所以就算了-- 总之就是个模拟题--没 ...
- box-shadow四周阴影
box-shadow 前面两个值为 纵向阴影 和 横向阴影 把这两个值都设置为 0 就是四边都有阴影 border:#074A99 0px solid; box-shadow: 0 0 10px #0 ...
- Spring使用_进阶
概述 本文主要写了几个关于Spring Aware,多线程,计划任务(定时任务),条件注解,组合注解,元注解,Spring测试的小例子以及关于@Enable*注解的工作原理的理解. Spring Aw ...
- 慢慢积累遇到的linux指令
sudo 用来以其他身份来执行命令,预设身份为root sudo apt install git 下载git sudo root 进入root身份(只有这个身份ubuntu和window系统之间才能共 ...
- 详解ASP.NET缓存机制
文中对ASP.NET的缓存机制进行了简述,ASP.NET中的缓存极大的简化了开发人员的使用,如果使用得当,程序性能会有客观的提升.缓存是在内存存储数据的一项技术,也是ASP.NET中提供的重要特性之一 ...
- UIView动画效果之----翻转.旋转.偏移.翻页.缩放.取反的动画效
翻转的动画 //开始动画 [UIView beginAnimations:@"doflip" context:nil]; //设置时常 [UIView setAnimationDu ...
- Linux中配置系统参数
[root@localhost ~]# vim /etc/security/limits.conf root soft nofile 65535root hard nofile 65535* soft ...
- SQLITE-更新查询
SQLite -更新查询 SQLite UPDATE查询用于修改现有表中的记录.您可以使用WHERE子句与更新查询更新选中的行,否则会被更新的所有行. 语法: UPDATE查询的WHERE子句的基本语 ...
- spring框架的总结
http://www.cnblogs.com/wangzn/p/6138062.html 大家好,相信Java高级工程师对spring框架都很了解吧!那么我以个人的观点总结一下spring,希望大家有 ...