Django: Oblicz sumę wartości kolumn za pomocą zapytania

92

Mam modelkę

class ItemPrice( models.Model ):
     price = models.DecimalField ( max_digits = 8, decimal_places=2 )
     ....

Próbowałem tego obliczyć sumę pricew tym zestawie zapytań:

items = ItemPrice.objects.all().annotate(Sum('price'))

co jest nie tak w tym zapytaniu? czy jest inny sposób obliczenia sumy pricekolumny?

Wiem, że można to zrobić za pomocą pętli for na queryset, ale potrzebuję eleganckiego rozwiązania.

Dzięki!

Ahsan
źródło
Czy to odpowiada na twoje pytanie? Django SUM Query?
Flimm

Odpowiedzi:

196

Prawdopodobnie szukasz aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example
MattH
źródło
1
Jak mogę uzyskać całkowitą liczbę, której cena = 5000?
Anuj Sharma,
6
Pamiętaj zwraca słownik, a nie liczbę zmiennoprzecinkową / całkowitą, np {'price__sum':1000}. Można uzyskać zmiennoprzecinkową / całkowitą zyourdict['price__sum']
Josh
35

Adnotacja dodaje pole do wyników:

>> Order.objects.annotate(total_price=Sum('price'))
<QuerySet [<Order: L-555>, <Order: L-222>]>

>> orders.first().total_price
Decimal('340.00')

Aggregate zwraca dyktę z pytanym wynikiem:

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}
Ibrohim Ermatov
źródło
Doceniam, że pokazałeś, jak określić, w którym ma keybyć przechowywana suma value.
MikeyE
32

Użyj .aggregate(Sum('column'))['column__sum']mojego przykładu Reefer poniżej

sum = Sale.objects.filter(type='Flour').aggregate(Sum('column'))['column__sum']
ugali miękkie
źródło
5

Używając profilera cProfile , stwierdzam, że w moim środowisku programistycznym wydajniejsze (szybsze) jest sumowanie wartości listy niż agregowanie przy użyciu Sum(). na przykład:

sum_a = sum([item.column for item in queryset]) # Definitely takes more memory.
sum_b = queryset.aggregate(Sum('column')).get('column__sum') # Takes about 20% more time.

Przetestowałem to w różnych kontekstach i wydaje się, że użycie aggregatezawsze trwa dłużej, aby uzyskać ten sam wynik. Chociaż podejrzewam, że pod względem pamięci może być korzyści, aby używać go zamiast sumowania listy.

Wujek Saam
źródło
1
Alternatywnie, użycie wyrażenia generatora zamiast listy: sum_a = sum(item.column for item in queryset). Jedyną różnicą jest usunięty []s. Oszczędza to miejsce w pamięci na obliczanie całej listy przed sum()iteracją po niej.
Code-Apprentice