2016-07-25 7 views
2

Sagen wir, es gibt einen Autor und er hat Bücher. Um Autoren zusammen mit der Anzahl der geschriebenen Seiten zu holen, kann folgendes geschehen:Annotate-Filterung - Summe nur einiger verwandter Objekte

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

Aber was, wenn ich Seiten von Science-Fiction-und Fantasy-Bücher getrennt summieren wollte? Ich möchte mit einem Autor enden, der die Eigenschaften total_pages_books_scifi_pages und total_pages_books_fantasy_pages hat.

Ich weiß, ich folgendes tun:

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')) 

Aber wie es in einem queryset?

Antwort

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

Versuchen:

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

Von Django docs: https://docs.djangoproject.com/en/1.10/topics/db/aggregation/#values:

Werte()

Normalerweise Anmerkungen auf einer pro-Objekt-Basis erzeugt werden - eine kommentierte QuerySet gibt ein Ergebnis für jedes Objekt im ursprünglichen QuerySet zurück. Wenn jedoch eine values ​​() -Klausel zum Beschränken der Spalten verwendet wird, die in der Ergebnismenge zurückgegeben werden, unterscheidet sich die Methode zum Auswerten von Anmerkungen etwas. Anstatt ein annotiertes Ergebnis für jedes Ergebnis im ursprünglichen QuerySet zurückzugeben, werden die ursprünglichen Ergebnisse gemäß den eindeutigen Kombinationen der in der values ​​() -Klausel angegebenen Felder gruppiert. Eine Annotation wird dann für jede eindeutige Gruppe bereitgestellt. Die Annotation wird für alle Mitglieder der Gruppe berechnet.

Verwandte Themen