Django: Обчислення суми значень стовпців за допомогою запиту


92

У мене є модель

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

Я спробував це для обчислення суми priceв цьому наборі запитів:

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

що не так у цьому запиті? чи існує інший спосіб обчислення суми priceстовпця?

Я знаю, що це можна зробити за допомогою циклу for на наборі запитів, але мені потрібно елегантне рішення.

Дякую!


Це відповідає на ваше запитання? Запит Django SUM?
Флімм

Відповіді:


196

Ви, мабуть, шукаєте aggregate

from django.db.models import Sum

ItemPrice.objects.aggregate(Sum('price'))
# returns {'price__sum': 1000} for example

1
Як я можу отримати загальну кількість, ціна якої = 5000?
Анудж Шарма

6
Запам'ятайте, повертає словник, не плаваючий / ціле число, наприклад {'price__sum':1000}. Можна отримати yourdict['price__sum']
Джош,

34

Анотація додає поле до результатів:

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

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

Агрегат повертає dict із запитуваним результатом:

>> Order.objects.aggregate(total_price=Sum('price'))
{'total_price': Decimal('1260.00')}

Я вдячний, що ви показали, як вказати keyдля зберігання суми value.
MikeyE

32

Використовуйте .aggregate(Sum('column'))['column__sum']мій приклад нижче

sum = Sale.objects.filter(type='Flour').aggregate(Sum('column'))['column__sum']

5

Використовуючи cProfile profiler , я виявляю , що в моєму середовищі розробки ефективніше (швидше) підсумовувати значення списку, ніж агрегувати за допомогою Sum(). наприклад:

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.

Я тестував це в різних контекстах, і, схоже, використання aggregateзавжди займає більше часу, щоб отримати однакові результати. Хоча я підозрюю, що можливо використовувати переваги з точки зору пам’яті замість підсумовування списку.


1
Як альтернативи, використовуйте вираз генератора замість списку: sum_a = sum(item.column for item in queryset). Різниця лише у видаленому []s. Це економить місце в пам’яті для обчислення всього списку перед його sum()ітерацією.
Code-Apprentice
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.