Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aggregate queryset to calculate percentage is always returning 0

Tags:

django

I'm trying to write a Django queryset that aggregates the percentage of verified contracts in our system. I can't seem to get it to work though - I'm always getting '0' for the percentage, even though I know that it should be closer to 25%.

My current attempts follows:

In[1]: Contract.objects.aggregate(
    total=Count('pk'),
    verified=Count('pk', filter=Q(verified_date__isnull=False)
)
Out[1]: {'total': 4000, 'verified': 1000}

In[2]: Contract.objects.aggregate(
    percentage=Count('pk', filter=Q(verified_date__isnull=False)) / Count('pk')
)
Out[2]: {'percentage': 0}

In[3]: Contract.objects.aggregate(
    percentage=Count('pk', filter=Q(verified_date__isnull=False), output_field=DecimalField()) / Count('pk', output_field=DecimalField())
)
Out[3]: {'percentage': Decimal('0')}

like image 474
notanumber Avatar asked Nov 25 '25 04:11

notanumber


1 Answers

You need to make the values decimal before dividing them, just multiply by 1.0 to make sure of that:

from django.db.models import ExpressionWrapper, Count, Value, DecimalField

Contract.objects.aggregate(perc=ExpressionWrapper(
    Count('pk', filter=Q(verified_date__isnull=False)) * Value(1.0) 
    / (Count('pk') * Value(1.0)), 
    output_field=DecimalField()))

I use ExpressionWrapper to be able to set the output_field parameter on the aggregation value itself.

UPDATE: After looking at this issue based on the comment that casting with output_field should have worked, I've found that this works as well:

from django.db.models import Count, DecimalField
from django.db.models.functions import Cast

Contract.objects.aggregate(perc=
    Cast(
        Count('pk', filter=Q(verified_date__isnull=False)), 
        DecimalField(max_digits=30, decimal_places=4)
    ) 
    / Cast(
        Count('pk'), 
        DecimalField(max_digits=30, decimal_places=4)
    )
)

The issue mentioned above explains why output_field doesn't work. Seems to be a tbd for the future :-)

like image 119
dirkgroten Avatar answered Nov 28 '25 00:11

dirkgroten



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!