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使用的更多相关文章

  1. django的聚合函数和aggregate、annotate方法使用

    支持聚合函数的方法: 提到聚合函数,首先我们要知道的就是这些聚合函数是不能在django中单独使用的,要想在django中使用这些聚合函数,就必须把这些聚合函数放到支持他们的方法内去执行.支持聚合函数 ...

  2. aggregate和annotate方法使用详解与示例

    aggregate和annotate方法的使用场景 Django的aggregate和annotate方法属于高级查询方法,主要用于组合查询.当我们需要对查询集(queryset)的某些字段进行计算或 ...

  3. [TimLinux] django aggregate和annotate示例

    1. 聚合与注解 聚合(aggregate)比较好理解,注解(annotate)真不好理解,这篇示例参考了文章“django中聚合aggregate和annotate GROUP BY的使用方法”提供 ...

  4. 72.Python中ORM聚合函数详解:Avg,aggregate,annotate

    聚合函数: 如果你用原生SQL语句,则可以使用聚合函数提取数据.比如提取某个商品销售的数量,那么就可以使用Count,如果想要知道销售的平均价格,那么就可以使用Avg. 聚合函数是通过aggregat ...

  5. Django的aggregate()和annotate()函数的区别

    aggregate() aggregate()为所有的QuerySet生成一个汇总值,相当于Count().返回结果类型为Dict. annotate() annotate()为每一个QuerySet ...

  6. django中聚合aggregate和annotate GROUP BY的使用方法

    接触django已经很长时间了,但是使用QuerySet查询集的方式一直比较低端,只会使用filter/Q函数/exclude等方式来查询,数据量比较小的时候还可以,但是如果数据量很大,而且查询比较复 ...

  7. Django ORM模型的一点体会

    作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...

  8. Django 模型和数据库 总结

    模型和数据库 模型 首先我们在创建一个model的时候,这个类都是继承自 django.db.models.Model, 各种Model Field类型 AutoField,自动增长的IntegerF ...

  9. Python数据库查询之组合条件查询-F&Q查询

    F查询(取字段的值) 关于查询我们知道有filter( ) ,values( ) , get( ) ,exclude( ) ,如果是聚合分组,还会用到aggregate和annotate,甚至还有万能 ...

随机推荐

  1. python错误之UnicodeEncodeError: 'ascii' codec can't encode characters in position 7-8: ordinal not in range(128)

    # coding = ascii import jsonimport pickleimport sysimport os decode()和encode方法中第一个参数为编码格式,第二个为出现无法转换 ...

  2. python入门之数据类型之列表、元组、字典

    list 格式: test_list = ["a",123,[1,"b"]] 索引: >>>print(test_list[0]) " ...

  3. HDU4576 Robot(概率)

    题意 抄袭自https://www.cnblogs.com/Paul-Guderian/p/7624039.html  多组输入n,m,l,r.表示在一个环上有n个格子.接下来输入m个w表示连续的一段 ...

  4. Android adb命令,linux中各种命令

    常用的ADB命令 1. 显示系统中全部Android平台: android list targets 2. 显示系统中全部AVD(模拟器): android list avd 3. 创建AVD(模拟器 ...

  5. fiddler+willow问题总结

    本文纯属用来记录自己学习过程中遇到的坑,如有朋友也遇到,可移步到这里查看是否为该问题导致. fiddler 安装不用说了,到官网直接去下载,自行下载最新版本 willow下载地址:http://qzo ...

  6. Azure School女神相邀,把每分钟都过的更充实

    也许你不姓「牛」,但是你技术牛啊 所以,请容我叫你一声「牛郎」 (讲真,只是因为你技术牛,不是其他啥原因哈) 平时忙到昏天黑地,一心一意为技术的你 注意看一下日历,因为: !!!七夕节(8月28日)到 ...

  7. 对InitialContext的理解

        类InitialContext java.lang.Object   javax.naming.InitialContext 此类是执行命名操作的初始上下文. 所有命名操作都相对于某一上下文. ...

  8. (五)maven之外置maven

    eclipse外置maven eclipse内置的maven插件是固定版本,如果要用其他版本的maven,可以使用外置maven. ①    在菜单栏上点击“Windows”à“Preferences ...

  9. 2017四川省赛E题( Longest Increasing Subsequence)

    提交地址: https://www.icpc-camp.org/contests/4rgOTH2MbOau7Z 题意: 给出一个整数数组,F[i]定义为以i结尾的最长上升子序列,然后问以此删除掉第i个 ...

  10. java并发编程:Executor、Executors、ExecutorService

    1.Executor和ExecutorService Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable comma ...