2012-08-28 14 views
30

Mam modelu niektóre rzeczy jak tenDjango Aggregation: Sumowanie mnożenie dwóch pól

class Task(models.Model): 
    progress = models.PositiveIntegerField() 
    estimated_days = models.PositiveIntegerField() 

Teraz chciałbym zrobić kalkulację Sum(progress * estimated_days) na poziomie bazy danych. Używanie Django Aggregation Mogę mieć sumę dla każdego pola, ale nie sumę mnożenia pól.

Odpowiedz

60

Aktualizacja: dla Django> = 1,8 proszę śledzić odpowiedzi dostarczonych przez @kmmbvnr

jest to możliwe przy użyciu Django ORM:

oto co powinieneś zrobić:

from django.db.models import Sum 

total = (Task.objects 
      .filter(your-filter-here) 
      .aggregate(
       total=Sum('progress', field="progress*estimated_days") 
      )['total'] 
     ) 

Uwaga: jeśli oba pola są różnych typów, np integer & float, rodzaj chcesz, aby powrócić powinna być przekazana jako pierwszy parametr Sum

Jest to późna odpowiedź, ale myślę, że to będzie pomóż komuś, kto szuka tego samego.

+1

Działa dobrze, dziękuję, ale uważaj, że * pole * kwarg nie jest udokumentowane i że nie znalazłem żadnego testu na ten temat w pakiecie testowym Django. –

+0

To jest fajne! Nadal działa na django 1.7. – haudoing

+0

co robi pole "postępu"?Próbuję obliczyć ten fragment kodu, ponieważ jest to dokładnie to, czego potrzebuję. – Maor

2

Czy masz kilka opcji:

  1. Raw query
  2. Emulbreh's undocumented approach
  3. Utwórz trzecie pole progress_X_estimated_days i aktualizować go w sposób oszczędzania nadpisywany. Następnie wykonaj agregację przez to nowe pole.

Nadpisywanie:

class Task(models.Model): 
    progress = models.PositiveIntegerField() 
    estimated_days = models.PositiveIntegerField() 
    progress_X_estimated_days = models.PositiveIntegerField(editable=False) 

    def save(self, *args, **kwargs): 
     progress_X_estimated_days = self.progress * self.estimated_days 
     super(Task, self).save(*args, **kwargs) 
+0

Tak, faktycznie utrzymując Raw SQL lub dodatkowy atrybut jako ostatnia opcja. W każdym razie dzięki. –

35

z Django 1.8 i powyżej można teraz przejść wyrażenie do agregatu:

from django.db.models import F 

Task.objects.aggregate(total=Sum(F('progress') * F('estimated_days')))['total'] 

Stałe są również dostępne, a wszystko to łączyć:

from django.db.models import Value 

Task.objects.aggregate(total=Sum('progress')/Value(10))['total'] 
+0

Myślę, że ta odpowiedź jest łatwiejsza do zrozumienia i utrzymania. Oprócz tego, jeśli typy tych pól są różne, dodaj parametr 'output_field' do agregacji funkcji –

+4

To jest aktualna poprawna odpowiedź. Dzięki –

+1

Próbuję go na django 1.7, ale otrzymuję AttributeError 'AttributeError: 'ExpressionNode' obiekt nie ma atrybutu" split ", dla jakiej wersji moja wersja django to 1.7.10 –

10

Rozwiązanie zależy od wersji Django.

  • Django < 1,8

    from django.db.models import Sum 
    MyModel.objects.filter(<filters>).aggregate(Sum('field1', field="field1*field2")) 
    
  • Django> = 1,8

    from django.db.models import Sum, F 
    MyModel.objects.filter(<filters>).aggregate(Sum(F('field1')*F('field2')))