Refs #7098 -- Deprecated passing raw column aliases to order_by().

Now that order_by() has expression support passing RawSQL() can achieve
the same result.

This was also already supported through QuerySet.extra(order_by) for
years but this API is more or less deprecated at this point.
This commit is contained in:
Simon Charette 2020-04-05 15:32:54 -04:00 committed by Mariusz Felisiak
parent 4237050684
commit 98ea4f0f46
4 changed files with 44 additions and 4 deletions

View File

@ -1895,7 +1895,16 @@ class Query(BaseExpression):
""" """
errors = [] errors = []
for item in ordering: for item in ordering:
if not hasattr(item, 'resolve_expression') and not ORDER_PATTERN.match(item): if isinstance(item, str) and ORDER_PATTERN.match(item):
if '.' in item:
warnings.warn(
'Passing column raw column aliases to order_by() is '
'deprecated. Wrap %r in a RawSQL expression before '
'passing it to order_by().' % item,
category=RemovedInDjango40Warning,
stacklevel=3,
)
elif not hasattr(item, 'resolve_expression'):
errors.append(item) errors.append(item)
if getattr(item, 'contains_aggregate', False): if getattr(item, 'contains_aggregate', False):
raise FieldError( raise FieldError(

View File

@ -69,6 +69,9 @@ details on these changes.
* ``django.views.generic.TemplateView`` will no longer pass URL kwargs directly * ``django.views.generic.TemplateView`` will no longer pass URL kwargs directly
to the ``context``. to the ``context``.
* Support for passing raw column aliases to ``QuerySet.order_by()`` will be
removed.
See the :ref:`Django 3.1 release notes <deprecated-features-3.1>` for more See the :ref:`Django 3.1 release notes <deprecated-features-3.1>` for more
details on these changes. details on these changes.

View File

@ -678,6 +678,10 @@ Miscellaneous
:class:`~django.views.generic.base.TemplateView` is deprecated. Reference :class:`~django.views.generic.base.TemplateView` is deprecated. Reference
them in the template with ``view.kwargs`` instead. them in the template with ``view.kwargs`` instead.
* Passing raw column aliases to :meth:`.QuerySet.order_by` is deprecated. The
same result can be achieved by passing aliases in a
:class:`~django.db.models.expressions.RawSQL` instead beforehand.
.. _removed-features-3.1: .. _removed-features-3.1:
Features removed in 3.1 Features removed in 3.1

View File

@ -7,10 +7,12 @@ from operator import attrgetter
from django.core.exceptions import EmptyResultSet, FieldError from django.core.exceptions import EmptyResultSet, FieldError
from django.db import DEFAULT_DB_ALIAS, connection from django.db import DEFAULT_DB_ALIAS, connection
from django.db.models import Count, Exists, F, OuterRef, Q from django.db.models import Count, Exists, F, OuterRef, Q
from django.db.models.expressions import RawSQL
from django.db.models.sql.constants import LOUTER from django.db.models.sql.constants import LOUTER
from django.db.models.sql.where import NothingNode, WhereNode from django.db.models.sql.where import NothingNode, WhereNode
from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext, ignore_warnings
from django.utils.deprecation import RemovedInDjango40Warning
from .models import ( from .models import (
FK1, Annotation, Article, Author, BaseA, Book, CategoryItem, FK1, Annotation, Article, Author, BaseA, Book, CategoryItem,
@ -609,14 +611,36 @@ class Queries1Tests(TestCase):
['datetime.datetime(2007, 12, 19, 0, 0)'] ['datetime.datetime(2007, 12, 19, 0, 0)']
) )
@ignore_warnings(category=RemovedInDjango40Warning)
def test_ticket7098(self): def test_ticket7098(self):
# Make sure semi-deprecated ordering by related models syntax still
# works.
self.assertSequenceEqual( self.assertSequenceEqual(
Item.objects.values('note__note').order_by('queries_note.note', 'id'), Item.objects.values('note__note').order_by('queries_note.note', 'id'),
[{'note__note': 'n2'}, {'note__note': 'n3'}, {'note__note': 'n3'}, {'note__note': 'n3'}] [{'note__note': 'n2'}, {'note__note': 'n3'}, {'note__note': 'n3'}, {'note__note': 'n3'}]
) )
def test_order_by_rawsql(self):
self.assertSequenceEqual(
Item.objects.values('note__note').order_by(
RawSQL('queries_note.note', ()),
'id',
),
[
{'note__note': 'n2'},
{'note__note': 'n3'},
{'note__note': 'n3'},
{'note__note': 'n3'},
],
)
def test_order_by_raw_column_alias_warning(self):
msg = (
"Passing column raw column aliases to order_by() is deprecated. "
"Wrap 'queries_author.name' in a RawSQL expression before "
"passing it to order_by()."
)
with self.assertRaisesMessage(RemovedInDjango40Warning, msg):
Item.objects.values('creator__name').order_by('queries_author.name')
def test_ticket7096(self): def test_ticket7096(self):
# Make sure exclude() with multiple conditions continues to work. # Make sure exclude() with multiple conditions continues to work.
self.assertQuerysetEqual( self.assertQuerysetEqual(