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:
parent
4237050684
commit
98ea4f0f46
|
@ -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(
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue