Ordering Django QuerySets by fields of related objects

This blog entry was posted by peter on November 26, 2007.

It is tagged with Django, and snippet.

So far there are 3 comments. Feel free to add one.

The previous entry chronologically is Fraunhofer IGD Multi-Touch Table.

In one of my Django applications I recently needed to sort a QuerySet by a field of a related object. And despite the fact that there is some documentation available it took me quite a while to solve the problem. In the end it was about one little detail and in order to save others from wasting their time I’ll shortly note what I did.

The model

The (simplified) model used to explain the issue contains only two fields, one of them being a ForeignKey to a User object from django.contrib.auth.

1
2
3
4
5
6
from django.contrib.auth.models import User
from django.db import models
class Learner(models.Model):
    ''' Model for a learner. '''
    user = models.ForeignKey(User)
    birthday = models.DateField()

The problem

Client: When displaying a list of Learner objects please sort it by the user’s lastname.
Me: No problem. Will be fixed in a minute.

1 hour later… 

My first approach was ordering the QuerySet by specifiying a default ordering via the model’s Meta field:

1
2
3
4
5
6
7
8
from django.contrib.auth.models import User
from django.db import models
class Learner(models.Model):
    ''' Model for a learner. '''
    user = models.ForeignKey(User)
    birthday = models.DateField()
    class Meta:
        ordering = [“auth_user.last_name”]  

But this results in the following error:

(1054, “Unknown column ‘auth_user.last_name’ in ‘order clause’”)

Next approach was to use the database API like described in in the official Django documentation and sort the QuerySet within the view function:

1
queryset = Learner.objects.all().order_by(“auth_user.last_name”)

But despite the fact that it’s described in the docs it gave me the same error again:

(1054, “Unknown column ‘auth_user.last_name’ in ‘order clause’”)

The solution 

To make a long story short, you need to use select_related() instead of all() and everything will work out fine:

1
queryset = Learner.objects.select_related().order_by(“auth_user.last_name”)

Comments

Comments are disabled for this entry.