Given a Django model which stores user transactions, how can I create a query that returns the average monthly spend for each user?
My current solution queries all the transactions , iterates the result and calculates the averages for each user using a dictionary. I am aware that there is a more efficient way to query this using aggregate/annotate
but unsure how to write it.
I am more concerned about readability than speed since the number of transactions in the db is relatively small and will never change.
models.py
Class Transactions(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey('User', on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=100, decimal_places=2)
date = models.DateField()
CodePudding user response:
Taking a late night stab at this (untested). The code below extracts out the year and month from the date, then clear the order with order_by() (may not be necessary in all cases), then group by the 'user', 'year', 'month' and calculate the average, storing in a column named 'average' by using the Avg function.
Documentation has some other good examples.
from django.db.models.functions import ExtractMonth, ExtractYear
from django.db.models import Avg
...
avg_by_user_by_month = Transactions.objects
.annotate(month=ExtractMonth('date'),
year=ExtractYear('date'),) \
.order_by()\
.values('user', 'year', 'month')\
.annotate(average=Avg('amount'))\
.values('user', 'year', 'month', 'average')