Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

199
Views
Complex aggregation in Django

Using Django rest framework 3.x and Django 1.1.10. I have a model that represents users. When I list all the users by accessing /users/ endpoint in DRF the list has to include some more data that is related to users via another model, called Owner. Each Item has an Owner and Owners have Users.

I made an extra property on the User model and it just returns a JSON array of the data. This is something that I can't change, because it is a requirement on the front-end. I have to return a total number of items that are related to each user and there are three different counts to perform to get the data.

I need to get multiple count()'s of items on the same model but with different conditions.

Doing these separately is easy, two are trivial and the last one is more complicated:

Item.objects.filter(owner__user=self).count()
Item.objects.filter(owner__user=self, published=True).count()
Item.objects.filter(Q(history__action__name='argle') | Q(history__action__name='bargle'),
                    history__since__lte=now,
                    history__until__gte=now,
                    owner__user=self).count()

The problem is because this is run for every user and there are many of them. In the end this generates more than 300 DB queries and I would like to bring these to a minimum.

So far I've came up with this:

Item.objects.filter(owner__user=self)\
            .aggregate(published=Count('published'),
                       total=Count('id'))

This will aggregate first two counts, return them and only one SELECT will be performed on the database. Is there a way to incorporate the last count() call into that same aggregate()?

I tried many things, but it seems impossible. Should I just write a custom SELECT and use Item.objects.raw()?

I also noticed that performing the aggregate() and the last count() is faster on my development machine and SQLite than on the staging server with Postgresql, which is a tad strange, but it's not my main concern right now.

about 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Since you require the counts for each item in your QuerySet you should use annotate instead of aggregate, this will then only perform 1 query.

The best way for counting related objects based on a condition is to use conditional aggregation

User.objects.annotate(
    total_items=Count('items'),
    published=Sum(Case(When(items__published=True, then=1), output_field=IntegerField())),
    foo=Sum(Case(When(
        Q(history__action__name='argle') | Q(history__action__name='bargle'),
        history__since__lte=now,
        history__until__gte=now,
        then=1
    ), output_field=IntegerField()))
)
about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!