Django aggregate sum for each user

Question:

I’m creating a budget application and wanted to find the sum of each user who’s signed in. Right now, I’m using function-based views and I sum up the expenses with Post.objects.aggregate(sum = Sum('expense')) The issue with this is it sums up everyone in the database but I wanted it to only sum up the expenses of the user that is currently signed in. In my model, I have an author field but I’m not sure how to go about summing only for the user currently signed in.

Asked By: Blizzard YT

||

Answers:

You can do something like this to get current user expense

Post.objects.filter(author=request.user).aggregate(sum = Sum('expense'))
this will return sum of current logged In user.

Answered By: Ankit Tiwari

You can annotate the sum for each user, with:

from django.db.models import Sum

User.objects.annotate(total=Sum('post__expense'))

The User objects that arises from this QuerySet will contain the sum of the expenses of the related posts.

For the logged in user, you can calculate this with:

from django.db.models import Sum

request.user.post_set.aggregate(total=Sum('expense'))['total'] or 0
Answered By: Willem Van Onsem

You can use aggregate() and annotate() with Sum() to sum up expense column in Post model user by user as shown below. *You need to use order_by('pk') with annotate() otherwise values are printed in descending order:

from django.db.models import Sum

for obj in User.objects.all(): 
    print(Post.objects.filter(user=obj).aggregate(Sum('expense')))

for obj in User.objects.all(): 
    print(obj.post_set.aggregate(Sum('expense')))

qs = User.objects.annotate(Sum('post__expense')).order_by('pk')
for obj in qs:
    print(obj.post__expense__sum)

And, you can change the default key expense__sum and post__expense to expenseSum for expense column as shown below:

from django.db.models import Sum

for obj in User.objects.all():                    # ↓ Here
    print(Post.objects.filter(user=obj).aggregate(expenseSum=Sum('expense')))

for obj in User.objects.all():   # ↓ Here
    print(obj.post_set.aggregate(expenseSum=Sum('expense')))
                           # ↓ Here
qs = User.objects.annotate(expenseSum=Sum('post__expense')).order_by('pk')
for obj in qs: # ↓ Here
    print(obj.expenseSum)
Answered By: Kai – Kazuya Ito