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.
Asked
Active
Viewed 772 times
1 Answers
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