Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to sort by a computed value in django

Hey I want to sort objects based on a computed value in django... how do I do it?

Here is an example User profile model based on stack overflow that explains my predicament:

class Profile(models.Model):
    user = models.ForeignKey(User)

    def get_reputation():
        ... 
        return reputation
    reputation = property(get_reputation)

So, say I want to sort users by reputation. How do I do that? I know you can't just do this:

Profile.objects.order_by("-reputation")

Thanks for your help everyone :)

like image 875
Jiaaro Avatar asked May 30 '09 23:05

Jiaaro


People also ask

How do I enable sorting in calculated field?

If you want to add sorting on a calculated field, you have to tell Django what to pass to order_by . You can do this by setting the admin_order_field attribute on the calculated field method.

What is f() in Django?

F() can be used to create dynamic fields on your models by combining different fields with arithmetic: company = Company. objects. annotate( chairs_needed=F('num_employees') - F('num_chairs')) If the fields that you're combining are of different types you'll need to tell Django what kind of field will be returned.

How to use aggregate function in 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.


3 Answers

Since your calculation code exists only within Python, you have to perform the sorting in Python as well:

sorted (Profile.objects.all (), key = lambda p: p.reputation)
like image 178
John Millikin Avatar answered Nov 13 '22 08:11

John Millikin


As of Django-1.8, it is possible to sort a QuerySet using query expressions as long as the computed value can be rendered in SQL. You can also use annotations to the model as the order_by term.

from django.db.models import F
Profile.objects.annotate(reputation=(F('<field>') + ...)).order_by("-reputation")

Basic operations like +, -, *, / and ** can be used with F(). In addition there are several other functions such as Count, Avg, Max, ...

Links:

  • Aggregation - order_by
  • Making Queries - filters can reference fields on a model
  • Query Expressions - Built in Expressions

See also this SO Q&A: Order a QuerySet by aggregate field value

like image 24
Mark Mikofski Avatar answered Nov 13 '22 09:11

Mark Mikofski


If you need to do the sorting in the database (because you have lots of records, and need to e.g. paginate them), the only real option is to turn reputation into a denormalized field (e.g. updated in an overridden save() method on the model).

like image 34
Carl Meyer Avatar answered Nov 13 '22 09:11

Carl Meyer