Класс Sum

Класс Sum применяется в методах aggregate и annotate для вычисления суммы значений числовых полей модели. Он принимает имя поля в качестве аргумента и возвращает выражение, которое преобразуется в SQL-запрос с функцией SUM. При работе с пустыми наборами записей возвращает None, если не указано иное через параметр default.

Синтаксис

pythonfrom django.db.models import Sum

# Использование в агрегации
Model.objects.aggregate(Sum('field_name'))

# Использование в аннотации
Model.objects.annotate(total=Sum('field_name'))

Пример

Рассмотрим модель Order с полями amount и status. Вычислим общую сумму всех заказов:

pythonfrom 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)

Результат выполнения кода:

python{'total_amount': Decimal('351.25')}

Пример

Используем Sum в комбинации с фильтрацией для подсчета суммы только выполненных заказов:

pythonfrom django.db.models import Sum
from myapp.models import Order

res = Order.objects.filter(status='completed').aggregate(
  completed_total=Sum('amount')
)
print(res)

Результат выполнения кода:

python{'completed_total': Decimal('301.25')}

Пример

Аннотируем каждый заказ дополнительным полем total_related, которое будет содержать сумму связанных позиций через внешний ключ:

pythonfrom 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}")

Результат выполнения кода:

python"Order 1: 350.00"
"Order 2: 200.00"

Пример

Используем параметр default для замены значения None при отсутствии записей в наборе данных:

pythonfrom 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)

Результат выполнения кода:

python{'cancelled_total': 0}

Пример

Вычислим сумму значений с использованием фильтрации через выражение Q для более сложных условий:

pythonfrom 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)

Результат выполнения кода:

python{'high_amount_sum': Decimal('200.75')}

Смотрите также

  • класс Count,
    который подсчитывает количество записей
  • класс Avg,
    который вычисляет среднее значение по полю
  • класс Min,
    который находит минимальное значение по полю
  • класс Max,
    который находит максимальное значение по полю