4

I'm working on a project which just moved to django 3.1. And I need to remove the usage of this "passing raw column aliases to QuerySet.order_by()" thing. However, I am not sure if my project is using it. So I need to understand how "passing raw column aliases to QuerySet.order_by()" actually works, if someone could provide me an example of the code that does the passing of raw column aliases to QuerySet.order_by(), it would be really helpful and appreciated.

Unknown
  • 41
  • 1

1 Answers1

5

tl;dr:

  • queries which use the dot-delimited syntax to refer to tables & column should be changed
  • queries which use __-delimited reference to tables & column are fine as-is

Runtime detection of deprecations

Well, first off the easiest way to detect use of deprecated patterns is to run your project and/or test suite with PYTHONWARNINGS=always or python -Wd. If you do that, you'll see some helpful warnings that can highlight exact lines where the bad pattern lives.

For example, a warning that is raised when you run my example code with Django 3.1:

RemovedInDjango40Warning: Passing column raw column aliases to order_by() is deprecated. Wrap '-auth_user_groups.id' in a RawSQL expression before passing it to order_by().
  User.objects.filter(groups__name='teachers').order_by('-auth_user_groups.id')

Example - fixing bad query

Consider the below - there are two queries, each of which will order teachers by tenure:

from django.contrib.auth.models import User
from django.db.models.expressions import RawSQL

# Deprecated!
# The value passed to `order_by` references a column on a table
User.objects.filter(groups__name='teachers').order_by('-auth_user_groups.id')

# Safe! We're now using RawSQL to make that same reference.
User.objects.filter(groups__name='teachers').order_by(
    RawSQL('auth_user_groups.id', tuple()).desc()
)

The two queries are equivalent, and translate to the (abbreviated) SQL:

SELECT auth_user.*
  FROM auth_user
 INNER JOIN auth_user_groups ON auth_user.id = auth_user_groups.user_id
 INNER JOIN auth_group ON auth_user_groups.group_id = auth_group.id
 WHERE auth_group.name = 'teachers'
 ORDER BY auth_user_groups.id DESC

Example - unaffected queries

Most queries don't make reference to table names & columns with the dot-delimited syntax, though.

These queries are just fine, and don't need to be changed:

from django.contrib.auth.models import User
from django.db.models.expressions import RawSQL

# Safe - we're ordering by `auth_user.date_joined`
User.objects.order_by('date_joined')

# Safe - we're ordering by `auth_group.name` after a JOIN on auth_group
User.objects.order_by('groups__name')
David Cain
  • 16,484
  • 14
  • 65
  • 75