Niladry Kar
Niladry Kar

Reputation: 1203

Django: unsupported operand type(s) for +: 'decimal.Decimal' and 'dict'

I am in my views.py and want to perform a mathamatical calculation for my accounting project...

So I have done something like this:

@login_required
def ledger1_detail_view(request,pk2, pk3):
    ledger1_details = get_object_or_404(ledger1, pk=pk2)
    selectdatefield_details = get_object_or_404(selectdatefield, pk=pk3)

    qs  = journal.objects.filter(User=request.user, Company=company_details.pk, By=ledger1_details.pk, Date__gte=selectdatefield_details.Start_Date, Date__lte=selectdatefield_details.End_Date)

    qs2 = journal.objects.filter(User=request.user, Company=company_details.pk, To=ledger1_details.pk, Date__gte=selectdatefield_details.Start_Date, Date__lte=selectdatefield_details.End_Date)    

    total_debit  = qs.aggregate(Sum('Debit'))

    total_credit = qs2.aggregate(Sum('Credit'))

   closing_balance = ledger1_details.Opening_Balance + total_debit - total_credit

    context = {

    'ledger1_details' : ledger1_details,
    'selectdatefield_details' : selectdatefield_details,
    'total_debit'     : total_debit,
    'total_credit'    : total_credit,
    'journal_debit'   : qs,
    'journal_credit'  : qs2,
    'closing_balance' : closing_balance,        

}   

return render(request, 'accounting_double_entry/ledger1_details.html', context)

The problem is in this line of code:

  closing_balance = ledger1_details.Opening_Balance + total_debit - total_credit

I am getting this error:

TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'dict'

This are my models:

class ledger1(models.Model):
    Creation_Date   = models.DateField(blank=True, null=True)
    name            = models.CharField(max_length=32)
    group1_Name     = models.ForeignKey(group1,on_delete=models.CASCADE,blank=True,null=True)
    Opening_Balance = models.DecimalField(max_digits=19,decimal_places=2,blank=True)

class journal(models.Model):
    Date       = models.DateField()
    By         = models.ForeignKey(ledger1,on_delete=models.CASCADE,related_name='Debitledgers')
    To         = models.ForeignKey(ledger1,on_delete=models.CASCADE,related_name='Creditledgers')
    Debit      = models.DecimalField(max_digits=10,decimal_places=2)
    Credit     = models.DecimalField(max_digits=10,decimal_places=2)

class selectdatefield(models.Model):
    Start_Date = models.DateField(blank=True, null=True)
    End_Date   = models.DateField(blank=True, null=True)

Do anyone have any idea about how to do this type of mathematical calculation in django views???

Upvotes: 0

Views: 1297

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

Your aggregates return dictionaries, not values, so:

# incorrect way to work with aggregates
total_debit  = qs.aggregate(Sum('Debit'))
total_credit = qs2.aggregate(Sum('Credit'))

# ... later you use these values like ...
closing_balance = ledger1_details.Opening_Balance + total_debit - total_credit

this will return:

# result of the above method
total_debit == { 'Debit__sum': 123 }
total_credit == { 'Credit__sum': 456 }

and it makes no sense to add a number (Decimal) together with a dictionary.

You can fetch the value that corresponds with the dictionary, so we need to unwrap these. Furthermore it might be possible that there are no related journal objects, in which case the outcome will be None, not 0.0, we can use the Coalesce [Django-doc] function for this:

# performing arithmetic with aggregates
from django.db.models import Value
from django.db.models.functions import Coalesce

total_debit = qs.aggregate(the_sum=Coalesce(Sum('Debit'), Value(0)))['the_sum']
total_credit = qs2.aggregate(the_sum=Coalesce(Sum('Credit'), Value(0)))['the_sum']
closing_balance = ledger1_details.Opening_Balance + total_debit - total_credit

You can also just fetch the 'sum__Debit' and 'sum__Credit' key, but personally I think named arguments are more "robust", since if you later change the aggregate, these will still work.

Upvotes: 4

Related Questions