Hassan Baig
Hassan Baig

Reputation: 15824

Using Django ORM to aggregate attribute value across filtered queryset

A django queryset contains user uploaded photos and their corresponding upvotes (from viewers).

I need to run a query which returns all the votes added together. Is there any way to use the ORM to return the aggregate votes? I'm assuming it would be faster than how I'm currently doing it (performance matters for me here).


Currently I'm trying the following:

yesterday = datetime.utcnow() - timedelta(hours = 24)
photos = Photo.objects.filter(upload_time__gte=yesterday)
cumulative_votes = 0
for photo in photos:
    cumulative_votes += photo.total_votes

Upvotes: 0

Views: 366

Answers (2)

Brian H.
Brian H.

Reputation: 844

here's a one-liner:

total_vote_sum = Photo.objects.filter(filter_stuff).aggregate(Sum("total_votes"))["total_votes__sum"]

quote from:
https://docs.djangoproject.com/es/1.10/topics/db/aggregation/#generating-aggregates-over-a-queryset

aggregate() is a terminal clause for a QuerySet that, when invoked, returns a dictionary of name-value pairs. The name is automatically generated from the name of the field and the aggregate function.

so queryset.aggregate(Sum('field')) will return a dictionary like:
{"field__sum": 'result'}

with this in mind, we can get our desired result directly like so:

result = queryset.aggregate(Sum('field'))['field__sum']

Upvotes: 1

Prakhar Trivedi
Prakhar Trivedi

Reputation: 8526

You need to use Sum,or Count functions of Django db, Like this :

from django.db.models import Count, Sum
yesterday = datetime.utcnow() - timedelta(hours = 24)

photos = Photo.objects.filter(upload_time__gte=yesterday).aggregate(total_votes=Count('total_votes'))
photo_sum = photos['total_votes']

Or

from django.db.models import Count, Sum
yesterday = datetime.utcnow() - timedelta(hours = 24)

photos = Photo.objects.filter(upload_time__gte=yesterday).aggregate(total_votes=Sum('total_votes'))
photo_sum = photos['total_votes']

Thanks.

Upvotes: 1

Related Questions