2

I have a model as follows:

class Loan(models.Model):
    lender = models.ForeignKey(User, related_name='lender')
    borrower = models.ForeignKey(User, related_name='borrower')
    money = models.IntegerField()

What I want to do is to calculate gross total for a user:

gross_total = Loans.object.filter(lender=user).annonate(Sum('money')) 
                - Loans.object.filter(borrower=user).annonate(Sum('money'))

My current total calculation is using two queries. I would like a single query for this.

Thanks.

Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63
s0nskar
  • 128
  • 2
  • 10

2 Answers2

4

This can be done with conditional expressions

from django.db.models import Case, Value, When, IntegerField

gross_total = Loans.object.aggregate(
    gross=Sum(
        Case(
            When(lender=user, then=F('money')),
            default=0, output_field=IntegerField)
        )
    ) - Sum(
        Case(
            When(borrower=user, then=F('money')),
            default=0, output_field=IntegerField)
        )
    )
)
Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63
0

Firstly, as you are using two Foreign Keys from the same User model, you need to give them a 'related_name' like this:

class Loan(models.Model):
    lender = models.ForeignKey(User, related_name='lender')
    borrower = models.ForeignKey(User, related_name='borrower')
    money = models.IntegerField()

Now coming to your question, what you need is something given in this post -> How to group by AND aggregate with Django

So the desired query for your question will most probably be:

gross_total = Loans.objects.filter(lender=user).values('user').annotate(score = Sum('money')) - Loans.objects.filter(borrower=user).values('user').annotate(score = Sum('money'))
Community
  • 1
  • 1
Ankush Raghuvanshi
  • 1,392
  • 11
  • 17
  • that's not what is want, I edited the question. btw thanks for that `value('user')` thing didn't knew about it – s0nskar Jul 20 '16 at 12:36
  • 1
    Not a problem. If you want to a single query, then I suppose you need an F() expression. See this -> https://docs.djangoproject.com/en/1.9/ref/models/expressions/ I'm trying to come up with the required answer to your updated question. If i will, then i'll add another answer. – Ankush Raghuvanshi Jul 20 '16 at 15:55