2016-09-07 4 views
0

Ich habe den folgenden Manager, der richtig funktioniert.Django Annotate- Gruppierung entlang mehrerer .annotate() Funktionen

def by_customer_and_date(self, start_date, end_date): 

    qs = self.model.objects.filter(
     date__range=(start_date, end_date) 
    ).values(
     "customer__name" 
    ).annotate(
     grand_total_cogs=Sum('total_cogs'), 
     total_sales=Sum('value'), 
     total_profit=Sum('profit'), 
     total_kgs=Sum('qty_applied'), 
     current_balance=Sum('sale__receiptallocation__qty_applied') 
    ).order_by('-total_kgs') 

Ergebnisse sind properly grouped nach Kundennamen von .values("customer__name")

jedoch verwenden, was ich möchte ist, dies zu tun:

def by_customer_and_date(self, start_date, end_date): 

    qs = self.model.objects.filter(
     date__range=(start_date, end_date) 
    ).values(
     "customer__name" 
    ).annotate(
     grand_total_cogs=Sum('total_cogs'), 
     total_sales=Sum('value'), 
     total_profit=Sum('profit'), 
     total_kgs=Sum('qty_applied'), 
     current_balance=Sum('sale__receiptallocation__qty_applied') 
    ).annotate(
     margin=Case(
      When(total_sales=0, then=0), 
      default=(F('profit'))/(F('value'))*100 
     ) 
    ).order_by('-total_kgs') 

ich die kommentierten Werte verwende einen anderen Wert zu berechnen, deren Nenner kann Null sein (daher die Verwendung von Case(When)). Wenn ich diesen Teil hinzufüge, verliert die .values("customer__name") Funktion ihren Effekt und jedes einzelne Element wird angezeigt.

Ich habe versucht, den .values("customer__name") Teil bis zum Ende zu verschieben (mit zusätzlichen expliziten Verweise auf jeden Feldnamen), aber das Problem bleibt.

Ist dies das beabsichtigte Verhalten? Gibt es einen Weg, um es zu umgehen?

Antwort

0

Ich habe festgestellt, dass die zweite annotate() am Ende des Ausdrucks platziert werden muss. Die richtige Reihenfolge dieser in meinem Beispiel sollte wie folgt lauten:

self.model.objects.filter().values().annotate().order_by().annotate()

Hier ist das Ergebnis:

def by_customer_and_date(self, start_date, end_date): 

    qs = self.model.objects.filter(
     date__range=(start_date, end_date) 
    ).values(
     "customer__name" 
    ).annotate(
     grand_total_cogs=Sum('total_cogs'), 
     total_sales=Sum('value'), 
     total_profit=Sum('profit'), 
     total_kgs=Sum('qty_applied'), 
     current_balance=Sum('sale__receiptallocation__qty_applied'), 
    ).order_by(
     '-total_kgs' 
    ).annotate(
     final_margin=Case(
      When(total_sales=0, then=0), 
      default=(Sum(F('profit'))/Sum(F('value')))*100 
     ) 
    ) 

    return qs