1. 程式人生 > 其它 >aggregate和annotate⽅法

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