Как выполнить условную агрегацию на связанном поле модели Django "один ко многим"?

Учитывая следующие схемы моделей:

class Transaction(models.Model):
  wallet = models.ForeignKey(related_name="transactions")
  amount = models.DecimalField()  # must be positive value
  type = models.CharField(choices=[("deposit", "deposit"), ("withdrawal", "withdrawal")]

class Wallet(models.Model):
  pass

Какой самый эффективный запрос Django ORM для получения баланса каждой записи кошелька в базе данных?

current_balance = sum of "amounts", where type="deposits" - sum of "amounts", where type="withdrawal"

Можно изменить поле Transaction модели type для хранения 1 & -1 целочисленных значений в базе данных и выполнить следующий запрос:

Wallet.objects.all().annotate(current_balance=Sum(F("transactions__amount") * F("transactions__type")))

Предположим, что мы не можем изменять столбцы или поля заданных таблиц/записей.

Мысли?

Возможно, мы можем работать с:

from django.db.models import Sum

Wallet.objects.annotate(
    balance=Sum('transactions__amount', filter=Q(transactions__type='deposit')) -
            Sum('transactions__amount', filter=Q(transactions__type='withdrawal'))
)

Но я бы посоветовал сделать сумму отрицательной в случае вывода средств, в этом случае мы можем просто суммировать транзакции с:

# when using negative amounts for withdrawals

from django.db.models import Sum

Wallet.objects.annotate(
    balance=Sum('transactions__amount')
)
Вернуться на верх