Django基础(24):aggregate和annotate⽅法使⽤详解与⽰例在前⾯的⽂章和案例⾥,我们从数据库⾥查询数据⼀般只使⽤了⼀些初级的查询⽅法⽐如filter()和exclude()⽅法。
四级报名官网报名系统但如果查询本⾝⽐较复杂,⽐如需要对查询集(queryt)的某些字段进⾏计算或进⾏分组计算或排序, 这时我们就需要使⽤更⾼级的aggregate和annotate⽅法了
aggregate和annotate⽅法的使⽤场景
Django的aggregate和annotate⽅法属于⾼级查询⽅法,主要⽤于组合查询,是Django⾼⼿们必需要熟练掌握的。当我们需要对查询集(queryt)的某些字段进⾏计算或进⾏先分组再计算或排序, 我们就需要使⽤aggregate和annotate⽅法了。
假如我们有如下⼀个模型,其中Student与Hobby(爱好)是多对多的关系。我们想要知道所有学⽣的平均年龄,我们常规做法⼀般是利⽤for循环从数据库中把符合查询条件的student对象⼀个⼀个取出,把他们年龄相加,然后再除以总⼈数。当⼈数⾮常多⽽我们⼜只需要平均年龄这条信息时,把所有符合查询条件的学⽣对象都载⼊内存后再进⾏计算是⾮常浪费资源的,效率也⾮常低。⼀个更好的⽅法是在数据库层⾯提取查询数据时就直接返回我们所需要的信息。因为这个查询涉及到对整个queryt的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()⽅法作⽤是对⼀组值(⽐如queryt的某个字段)进⾏统计计算,并以字典(Dict)格式返回统计计算结果。
django的aggregate⽅法⽀持的聚合操作有AVG / COUNT / MAX / MIN /SUM 等。
我们现在来看下⼏组实际使⽤案例。使⽤前别忘了import Avg, Max, Min或者Sum⽅法哦
from dels import Avg, Max, Min
# 计算学⽣平均年龄, 返回字典。age和avg间是双下划线哦
Student.objects.all().aggregate(Avg('age'))
{ 'age__avg': 12 }
# 学⽣平均年龄,返回字典。all()不是必须的。
complexityStudent.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 }
# 同时获取学⽣年龄均值, 最⼤值和最⼩值, 返回字典lane
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'))
syndrome{ 'student__age__max': 12 }
你注意到了吗? aggregate⽅法返回Dict类型数据和django的内容对象(context object)是⼀样的哦。你可以很轻松地将结果传递给模板, 在模板中显⽰。
annotate()⽅法详解
annotate的中⽂意思是注释,⼩编我觉得是⾮常地词不达意,⼀个更好的理解是分组(Group By)。如果你想要对数据集先进⾏分组然后再进⾏某些聚合操作或排序时,需要使⽤annotate⽅法来实现。与aggregate⽅法不同的是,annotate⽅法返回结果的不仅仅是含有统计结果的⼀个字典,⽽是包含有新增统计字段的查询集(queryt).
我们接下来也看下⼏个实际使⽤案例。
attackpower
# 按学⽣分组,统计每个学⽣的爱好数量
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]报关英文
column是什么意思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⽅法属于⾼级查询⽅法,主要⽤于组合查询,可以⼤⼤提升数据库查询效率。当你需要对查询集(queryt)的某些字段进⾏聚合操作时(⽐如Sum, Avg, Max),请使⽤aggregate⽅法。如果你想要对数据集先进⾏分组(Group By)然后再进⾏某些聚合操作或排序时,请使⽤annotate⽅法。最后希望本⽂提供的⼀些⽰例对你有所帮助哦。