aggregate和annotate⽅法
现在来看下⼏组实际使⽤案例。使⽤前别忘了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’))
现在来看下⼏组实际使⽤案例。使⽤前别忘了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⽅法。最后希望本⽂提供的⼀些⽰例对你有所帮助哦
调用案例:
from django.db.models import Sum def result_test(request): var = request.POST.get('selectedTests') booktests = BookTest.objects.filter(test__in=var.split(',')) total_rate = booktests.aggregate(total=Sum('rate'))['total'] or 0