Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ordering a django queryset by sum of two (or more) fields

Tags:

django

I have found a few questions that are similar to mine, but most of them are dated, or too (or too little) verbose to be helpful.

I have a model like this:

class Breakfast(models.Model):
    count_eggs = models.IntegerField()
    count_bacon = models.IntegerField()
    had_toast = models.BooleanField()

Now, in building a RESTful API, I need the ability to sort Breakfast objects by the total of count_eggs + count_bacon without storing this permanently on the model.

Many of the current and popular questions suggest something like this:

Breakfast.objects.extra(
    select={'total_food':'count_eggs + count_bacon'},
    order_by=('total_food',)
)

This seems to work for many, but Django docs appear to dissuade this solution. So, in the 1.10+ world, What is the best/correct way to do this type of filtering on the sum of two (or more) fields in Django

like image 336
rob Avatar asked Dec 11 '17 17:12

rob


People also ask

Is Django QuerySet ordered?

By default, results returned by a QuerySet are ordered by the ordering tuple given by the ordering option in the model's Meta . You can override this on a per- QuerySet basis by using the order_by method. The result above will be ordered by pub_date descending, then by headline ascending.

How to aggregate Django?

When specifying the field to be aggregated in an aggregate function, Django will allow you to use the same double underscore notation that is used when referring to related fields in filters. Django will then handle any table joins that are required to retrieve and aggregate the related value.

What is annotate in Django?

Appending the annotate() clause onto a QuerySet lets you add an attribute to each item in the QuerySet, like if you wanted to count the amount of articles in each category. However, sometimes you only want to count objects that match a certain condition, for example only counting articles that are published.


1 Answers

You should use annotate, I got an example of mine and adapted to your case, try this:

from django.db.models import F, Sum

Breakfast.objects.all().\
            annotate(total_food=Sum(
                F('count_eggs ') + F('count_bacon'))
            ).\
            order_by('total_food')
like image 120
Latrova Avatar answered Oct 05 '22 12:10

Latrova