aggregate和annotate方法使用详解与示例
aggregate和annotate方法的使用场景
Django的aggregate和annotate方法属于高级查询方法,主要用于组合查询。当我们需要对查询集(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方法使用详解与示例的更多相关文章
- CentOS 6.3下Samba服务器的安装与配置方法(图文详解)
这篇文章主要介绍了CentOS 6.3下Samba服务器的安装与配置方法(图文详解),需要的朋友可以参考下 一.简介 Samba是一个能让Linux系统应用Microsoft网络通讯协议的软件, ...
- jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解
jQuery操纵DOM元素属性 attr()和removeAtrr()方法使用详解 jQuery中操纵元素属性的方法: attr(): 读或者写匹配元素的属性值. removeAttr(): 从匹配的 ...
- php课程---Windows.open()方法参数详解
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- Window.open()方法参数详解
Window.open()方法参数详解 1, 最基本的弹出窗口代码 window.open('page.html'); 2, 经过设置后的弹出窗口 window.open('page.html ...
- 集合类 Contains 方法 深入详解 与接口的实例
.Net 相等性:集合类 Contains 方法 深入详解 http://www.cnblogs.com/ldp615/archive/2009/09/05/1560791.html 1.接口的概念及 ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
- C#虚方法virtual详解
转: http://www.cnblogs.com/jason_yjau/archive/2009/08/25/1553949.html C#虚方法virtual详解 在C++.Java等众多OOP语 ...
- JQuery动画animate的stop方法使用详解
JQuery动画animate的stop方法使用详解 animate语法: 复制代码 代码如下: $(selector).animate(styles,speed,easing,callback) 复 ...
- Linux NFS服务器的安装与配置方法(图文详解)
这篇文章主要介绍了Linux NFS服务器的安装与配置方法(图文详解),需要的朋友可以参考下(http://xb.xcjl0834.com) 一.NFS服务简介 NFS 是Network File S ...
随机推荐
- How to Compare Means (均值比较)
在比较数据的均值时,我们可能知道: 比较工厂当天生产的零件的长度是否合格 (length >= N mm),用 t-Test; 比较各一线城市的人均收入,用 ANOVA. 其实均值比较还有很多检 ...
- 【POJ - 1458】Common Subsequence(动态规划)
Common Subsequence Descriptions: A subsequence of a given sequence is the given sequence with some e ...
- 题解报告:hdu 2084 数塔(递推dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2084 Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这 ...
- JetSpeed2部署至Apusic操作步骤记录
JetSpeed2部署至Apusic操作步骤记录. 1.创建Apusic新域,配置端口.管理端口和管理密码. 2.将Tomcat/lib目录中的所有jar包复制至Apusic域中的lib目录中(包括数 ...
- foreach的学习使用归纳
1: 实现对双向链表的遍历使用 LinkedList<string> llary = new LinkedList<string>(); llary.AddLast (&quo ...
- 员工管理系统(集合与IO流的结合使用 beta1.0 ArrayList<Employee>)
package cn.employee; public class Employee { private int empNo; private String name; private String ...
- 配置maven环境变量cmd控制台提示:mvn不是内部或外部命令,也不是可运行的程序或批处理文件
配置maven环境变量cmd控制台提示:mvn不是内部或外部命令,也不是可运行的程序或批处理文件 首先maven环境变量: 变量名:MAVEN_HOME 变量值:E:\apache-maven-3.2 ...
- c#中stringbuilder的方法总结
String 对象是不可改变的.每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需要对字符串执行重复修改的情况下,与创建新 ...
- 面相切面编程AOP以及在Unity中的实现
一.AOP概念 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.它是 ...
- 学习笔记 第十五章 JavaScript基础
第15章 JavaScript基础 [学习重点] 了解JavaScript基础知识 熟悉常量和变量 能够使用表达式和运算符 正确使用语句 能够掌握数据类型和转换的基本方法 正确使用函数.对象.数组 ...