Home > Net >  Can't aggregate a DecimalField in Django
Can't aggregate a DecimalField in Django

Time:04-29

I have a queryset where I want to aggregate the fields amount which itself is a DecimalField. The target field is also a DecimalField.

I get this error:

django.core.exceptions.ValidationError: ["“{'amount__sum': Decimal('3821.02000000000')}” value must be a decimal number."]

Why does it say it must be a decimal number even though it is a DecimalField?

# models.py

class Payment(models.Model):

    offer = models.ForeignKey(Offer, on_delete=models.CASCADE)
    month = models.ForeignKey(Period, on_delete=models.CASCADE)
    payroll_run = models.ForeignKey(Payroll, on_delete=models.CASCADE, null=True, blank=True)  # is populated once the payroll run was created

    amount = models.DecimalField(decimal_places=2, max_digits=10)


class Payroll(models.Model):

    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    month = models.DateField()
    amount = models.DecimalField(decimal_places=2, max_digits=10)
    line_items = models.PositiveIntegerField()
def test():
   ...

    # Loop the companies
    for company in qs_companies:
        # Query all Payments of that company in that month
        qs_payments = Payment.objects.filter(offer__company=company).filter(month=period)

        # Create a payroll run instance
        payroll_run = Payroll.objects.create(
            company=company,
            month=next_payroll_run,
            amount=qs_payments.aggregate(Sum('amount')),
            line_items=qs_payments.count()
        )

        payroll_run.save()
   ...

CodePudding user response:

aggregate() returns a dictionary, you need to pass your aggregated value and not the whole dict

        payroll_run = Payroll.objects.create(
            company=company,
            month=next_payroll_run,
            amount=qs_payments.aggregate(Sum('amount'))['amount__sum'], # <- added the lookup
            line_items=qs_payments.count()
        )

EDIT: From Django 4.0 you can add a default argument to Sum

amount=qs_payments.aggregate(Sum('amount', default=Decimal(0)))['amount__sum']
  • Related