Класс Sum
Класс Sum применяется в методах aggregate и annotate для вычисления суммы значений
числовых полей модели. Он принимает имя поля в качестве аргумента и возвращает выражение,
которое преобразуется в SQL-запрос с функцией SUM. При работе с пустыми наборами записей
возвращает None, если не указано иное через параметр default.
Синтаксис
from django.db.models import Sum
# Использование в агрегации
Model.objects.aggregate(Sum('field_name'))
# Использование в аннотации
Model.objects.annotate(total=Sum('field_name'))
Пример
Рассмотрим модель Order с полями amount и status.
Вычислим общую сумму всех заказов:
from django.db import models
from django.db.models import Sum
class Order(models.Model):
amount = models.DecimalField(max_digits=10, decimal_places=2)
status = models.CharField(max_length=20)
# Создаем несколько заказов
Order.objects.create(amount=100.50, status='completed')
Order.objects.create(amount=200.75, status='completed')
Order.objects.create(amount=50.00, status='pending')
res = Order.objects.aggregate(total_amount=Sum('amount'))
print(res)
Результат выполнения кода:
{'total_amount': Decimal('351.25')}
Пример
Используем Sum в комбинации с фильтрацией для подсчета суммы только выполненных заказов:
from django.db.models import Sum
from myapp.models import Order
res = Order.objects.filter(status='completed').aggregate(
completed_total=Sum('amount')
)
print(res)
Результат выполнения кода:
{'completed_total': Decimal('301.25')}
Пример
Аннотируем каждый заказ дополнительным полем total_related,
которое будет содержать сумму связанных позиций через внешний ключ:
from django.db import models
from django.db.models import Sum
class Order(models.Model):
status = models.CharField(max_length=20)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.IntegerField()
orders = Order.objects.annotate(
total_items=Sum('orderitem__price')
)
for order in orders:
print(f"Order {order.id}: {order.total_items}")
Результат выполнения кода:
"Order 1: 350.00"
"Order 2: 200.00"
Пример
Используем параметр default для замены значения None
при отсутствии записей в наборе данных:
from django.db.models import Sum
from myapp.models import Order
res = Order.objects.filter(status='cancelled').aggregate(
cancelled_total=Sum('amount', default=0)
)
print(res)
Результат выполнения кода:
{'cancelled_total': 0}
Пример
Вычислим сумму значений с использованием фильтрации через выражение Q
для более сложных условий:
from django.db.models import Sum, Q
from myapp.models import Order
res = Order.objects.aggregate(
high_amount_sum=Sum('amount', filter=Q(amount__gt=100))
)
print(res)
Результат выполнения кода:
{'high_amount_sum': Decimal('200.75')}