I have a table with the following values:
user | amount | date |
---|---|---|
John | 10 | 2017-07-01 |
John | 20 | 2019-07-01 |
John | 30 | 2020-09-01 |
John | 40 | 2021-11-01 |
... | ... | ... |
Dan | -20 | 2019-02-01 |
Dan | -30 | 2020-04-01 |
Dan | -40 | 2021-06-01 |
The input of the function is a range of date, for example, as follows:
date_start = '2019-01-01'
date_end = '2021-11-07'
Expected output:
For all users, for each date in this range of date, I want to return the sum
of the amounts
, from the current date to all previous dates like this:
user | amount | date |
---|---|---|
John | 30 (10 20) |
2019-07-01 |
John | 60 (10 20 30) |
2020-09-01 |
John | 100 (10 20 30 40) |
2021-11-01 |
... | ... | ... |
Dan | -20 | 2019-02-01 |
Dan | -50 (-20-30) |
2020-04-01 |
Dan | -90 (-20-30-40) |
2021-06-01 |
My efforts
def get_sum_amount(self, date_start=None, date_end=None):
date_detail = {}
# Minimum date
if date_start:
date_detail['date__gt'] = date_start
# Maximum date
if date_end:
date_detail['date__lt'] = date_end
detail = Financial.objects.filter(Q(**date_detail)) \
.values('user') \
.annotate(sum_amount=Coalesce(Sum(F('amount')), Value(0)))
but no result.
UPDATED
The output of the function for the above example is:
user | amount |
---|---|
John | 100 |
Dan | -90 |
CodePudding user response:
You can use Window
functions with a partition onuser
to run a cumulative sum per user, ordered by the date:
detail = Financial.objects.filter(**date_detail).annotate(
running_amount=Window(
expression=Sum('amount'),
partition_by=[F('user')],
order_by=F('date').asc(),
)
)