Django фильтрация агрегированного запроса после агрегирования
У меня есть модель транзакции:
class transaction(models.Model):
transactiondate = models.DateField()
details = models.CharField(max_length=200, null=True)
amount = models.DecimalField(decimal_places=2, max_digits=10)
accountid = models.ForeignKey(account, on_delete=models.PROTECT)
Я пытаюсь получить текущий общий баланс на каждую дату, чтобы я мог построить баланс за последние 12 месяцев на линейной диаграмме. Мой запрос таков:
transaction.objects.annotate(
balance=Window(Sum('amount'), order_by=F('transactiondate').asc())).filter(transactiondate__gte='2021-01-01')
Проблема в том, что это не включает данные до 2021-01-01 в расчет. Я хочу, чтобы сумма включала все транзакции независимо от даты, но я хочу видеть на графике только 12 месяцев. Я думал, что метка на фильтре после агрегата сначала рассчитает правильный баланс, а затем применит фильтр, чтобы дать мне только 12 месяцев, но это не то, что происходит. Если я удалю фильтр, то получу правильный баланс, но мой линейный график нечитабелен при таком количестве данных.
Есть ли способ фильтровать данные после агрегации?
Что-то вроде следующего должно работать с использованием Subquery. Производительность может быть хуже, чем при использовании оконного выражения
from django.db.models import Sum, OuterRef, Subquery
previous_transactions = Transaction.objects.filter(transactiondate__lte=OuterRef('transactiondate')).order_by().values('amount')
balances = previous_transactions.annotate(balance=Sum('amount')).values('balance')
annotated = Transaction.objects.order_by('transactiondate').annotate(balance=Subquery(balances)).filter(transactiondate__gte='2021-01-01')
Django выполняет group by
с помощью values
. Поэтому я думаю, что вам нужно сгруппировать по каждой дате, вы можете использовать следующий запрос.
import datetime
from django.db.models import Sum
from django.utils import timezone
transaction.objects.filter(
transactiondate__gte=timezone.now().date()-timedeleta(months=12) # previous twelve months data
).values(
'transactiondate' # this does the group by on date
).annotate(
balance = Sum('amount') # aggregates the amount on each date
).values('transactiondate', 'balance')