user9745220
user9745220

Reputation: 253

Django: Add objects.all.count() to aggregate?

I've been searching how to add X.objects.all().count() result to an existing aggregate logic. I seen that Count() will only work with a foreign key relationship, so how can I add an 'additional field' with the .count() results to the aggregate with only writing it in one block.

This is my custom action (Does not work):

    from django.db.models.functions import Coalesce
    from django.db.models import Min, Avg, Max, Value as Val, IntegerField

    @action(detail=False, methods=['get'])
    def get_stats(self, request, pk=None):
        total_ads = Ad.objects.all().count()
    
        stats = Ad.objects.aggregate(
            price_min = Coalesce(Min('price'), Val(0)), 
            price_avg = Coalesce(Avg('price'), Val(0.0)),
            price_max = Coalesce(Max('price'), Val(0)),
            ads_total = Val(total_ads, output_field=IntegerField()),
        )
    
        return Response(stats)

Error: TypeError: ads_total is not an aggregate expression

Upvotes: 1

Views: 408

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477318

I seen that Count() will only work with a foreign key relationship, so how can I add an 'additional field' with the .count()

You can also Count the primary key, which will count any non-NULL item, you thus can use:

stats = Ad.objects.aggregate(
    price_min=Coalesce(Min('price'), Val(0)), 
    price_avg=Coalesce(Avg('price'), Val(0.0)),
    price_max=Coalesce(Max('price'), Val(0)),
    ads_total=Count('pk')
)

and you thus can omit the total_ads = Ad.objects.all().count() query, and reduce the number of queries to one.

Upvotes: 2

Related Questions