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,甚至还有万能 ...
随机推荐
- idea | SpringBoot项目热加载
第一步: 在pom文件添加依赖: <dependency> <groupId>org.springframework.boot</groupId> <arti ...
- Other Linker Flags里加上所需的参数
在Other Linker Flags里加上所需的参数,用到的参数一般有以下3个: -ObjC -all_load -force_load 下面来说说每个参数存在的意义和具体做的事情. 首先是-Obj ...
- TCP长链接调试利器nc
最近做了不少TCP长链接的开发,包括服务端和客户端.本人感觉服务器端与客户端通信时最好采用字符串形式,这样可以做要平台无关,跨语言.如果采用对象序列化机制通用性会较差.另外采用字符串形式用nc调试很方 ...
- shell与aw的简单交互示例
先来看一段shell代码 word=“a test name” selectword=“test"lineitem=`echo "$word" | awk 'match( ...
- Java GUI 顶级容器JFrame、JDialog
JFrame的常用构造函数: JFrame() JFrame(String title) //窗口标题,会显示在左上角窗体图标的后面 JDialog的常用构造函数: JDialog() JDial ...
- GIMP 无法设置中文的问题解决
首先按照网上说的安装了language-pack-gnome-zh-hant 参考链接:http://www.ubuntu-tw.org/modules/newbb/viewtopic.php?top ...
- 打开一个本地apk进行安装
Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); File file = new File(Environment ...
- APP启动原理
当我们点击一个应用的时候,系统会自动创建一个相应的activity类实例,然后执行Oncreate方法,接着会执行以下两行代码,解释如下: super.onCreate(savedInstanceSt ...
- HDU 1964 Pipes (插头DP,变形)
题意:给一个n*m的矩阵,每个格子都是必走的,且无障碍格子,每对格子之间都有一个花费,问哈密顿回路的最小花费. 思路: 这个和Formula1差不多,只是求得是最小花费,这只需要修改一下DP值为花费就 ...
- Servlet和JSP之有关Servlet和JSP的梳理(一)
大二第一学期的时候有学JSP的课,但是因为在开学之前做过JSP的小项目,所以一个学期的课也没听,直到期末考试成绩出来了,才回想JSP的内容还有多少记得,没想到模模糊糊也记不起多少,赶紧回头学回来.接下 ...