2016-07-25 51 views
2

假設有一個作者,他有書籍。爲了與書面頁的數量一起取的作者,下面可以做:註釋過濾 - 只彙總一些相關對象的字段

Author.objects.annotate(total_pages=Sum('book__pages')) 

但是,如果我想總結科幻與幻想書籍單獨的頁面是什麼?我想結束一個作者,它有total_pages_books_scifi_pages和total_pages_books_fantasy_pages屬性。

我知道我可以做如下:

Author.objects.filter(book__category='scifi').annotate(total_pages_books_scifi_pages=Sum('book__pages')) 
Author.objects.filter(book__category='fantasy').annotate(total_pages_books_fantasy_pages=Sum('book__pages')) 

但在一個查詢集怎麼辦呢?

回答

6
from django.db.models import IntegerField, F, Case, When, Sum 

categories = ['scifi', 'fantasy'] 
annotations = {} 

for category in categories: 
    annotation_name = 'total_pages_books_{}'.format(category) 
    case = Case(
     When(book__category=category, then=F('book__pages')), 
     default=0, 
     output_field=IntegerField() 
    ) 
    annotations[annotation_name] = Sum(case) 

Author.objects.filter(
    book__category__in=categories 
).annotate(
    **annotations 
) 
2

嘗試:

Author.objects.values("book__category").annotate(total_pages=Sum('book__pages')) 

從Django文檔: https://docs.djangoproject.com/en/1.10/topics/db/aggregation/#values

值()

通常,基於每個對象的基礎上生成的註釋 - 一個註釋QuerySet將爲原始QuerySet中的每個對象返回一個結果。但是,如果使用values()子句來限制結果集中返回的列,則評估註釋的方法稍有不同。原始結果不是針對原始QuerySet中的每個結果返回註釋結果,而是根據values()子句中指定的字段的唯一組合來分組。然後爲每個唯一的組提供註釋;該註解是針對該組的所有成員進行計算的。