2016-08-04 9 views
2

ich folgende Modell-Manager habe, die auf einem SalesRecord betreiben:Django - mit Anmerkungen versehen gewichteten AVG von Gruppe

def by_variety_and_date(self, start_date, end_date): 
    return self.model.objects.filter(
     date__range=(start_date, end_date) 
    ).values(
     "variety" 
    ).annotate(
     qty_applied=Sum('qty_applied'), 
     margin=Avg('margin') 
    ) 

Was ich wirklich mag, ist für die margin=Avg('margin') einen gewichteter Durchschnitt zurückzukehren, basierend auf qty_applied. Gibt es eine Möglichkeit, dies mit Djangos Annotate/Aggregat-Abfragen zu tun? Ich experimentiere mit dem Stringing .aggregate() bis zum Ende davon, aber ich möchte immer noch den Durchschnittswert pro variety wie von diesem Queryset beschrieben.

Das Modell in diesem Fall wie folgt aussieht:

class Sale(models.Model): 
    margin = models.DecimalField(null=True, blank=True, decimal_places=2, max_digits=12) 
    qty_applied = models.IntegerField(null=True, blank=True) 
    variety = models.ForeignKey(Variety, null=True) 
    totals = Totals() 

EDIT

Dies ist, was ich schließlich mit endete. Es ist ein bisschen wackelig, aber es macht den Trick.

def by_variety_and_date(self, start_date, end_date): 
    return self.model.objects.filter(
     date__range=(start_date, end_date) 
    ).values(
     "variety" 
    ).annotate(
     qty_applied=Sum('qty_applied'), 
     profit=Sum('profit'), 
     cogs=Sum('cogs'), 
     sales=Sum('value'), 
     margin=Sum(
      (F('qty_applied')*F('margin')), output_field=FloatField() 
     )/Sum(
      'qty_applied', output_field=FloatField()) 
    ) 

habe ich die F-Objekte als @WTower jedes Objekt zu multiplizieren vorgeschlagen margin von seinen qty_applied, dann das Ganze in einem Sum gewickelt und geteilt durch die Sum der qty_applied alle Objekte in der Gruppe. Klappt wunderbar!

Antwort

3

können Sie die F() expression

>>> from django.db.models import F, FloatField, Sum 
>>> MyModel.objects.all().aggregate(
... w_avg=Sum((F('a')*F('b'))/F('b'), output_field=FloatField())) 

Mehr zu here Aggregation verwenden.

Alternativ können Sie benutzerdefinierte SQL (nicht empfohlen) oder eine benutzerdefinierte Methode im Manager verwenden.

+0

Kein benutzerdefiniertes SQL benötigt :). Dies ist eine benutzerdefinierte Managermethode, übrigens. –

Verwandte Themen