Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5139487

Browse files
charettesfelixxm
authored andcommitted
Fixed #31426 -- Added proper field validation to QuerySet.order_by().
Resolve the field reference instead of using fragile regex based string reference validation.
1 parent 98ea4f0 commit 5139487

3 files changed

Lines changed: 19 additions & 19 deletions

File tree

django/db/models/sql/constants.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
Constants specific to the SQL storage portion of the ORM.
33
"""
44

5-
from django.utils.regex_helper import _lazy_re_compile
6-
75
# Size of each "chunk" for get_iterator calls.
86
# Larger values are slightly faster at the expense of more storage space.
97
GET_ITERATOR_CHUNK_SIZE = 100
@@ -16,7 +14,6 @@
1614
CURSOR = 'cursor'
1715
NO_RESULTS = 'no results'
1816

19-
ORDER_PATTERN = _lazy_re_compile(r'\?|[-+]?[.\w]+$')
2017
ORDER_DIR = {
2118
'ASC': ('ASC', 'DESC'),
2219
'DESC': ('DESC', 'ASC'),

django/db/models/sql/query.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@
3030
from django.db.models.query_utils import (
3131
Q, check_rel_lookup_compatibility, refs_expression,
3232
)
33-
from django.db.models.sql.constants import (
34-
INNER, LOUTER, ORDER_DIR, ORDER_PATTERN, SINGLE,
35-
)
33+
from django.db.models.sql.constants import INNER, LOUTER, ORDER_DIR, SINGLE
3634
from django.db.models.sql.datastructures import (
3735
BaseTable, Empty, Join, MultiJoin,
3836
)
@@ -1895,7 +1893,7 @@ def add_ordering(self, *ordering):
18951893
"""
18961894
errors = []
18971895
for item in ordering:
1898-
if isinstance(item, str) and ORDER_PATTERN.match(item):
1896+
if isinstance(item, str):
18991897
if '.' in item:
19001898
warnings.warn(
19011899
'Passing column raw column aliases to order_by() is '
@@ -1904,6 +1902,18 @@ def add_ordering(self, *ordering):
19041902
category=RemovedInDjango40Warning,
19051903
stacklevel=3,
19061904
)
1905+
continue
1906+
if item == '?':
1907+
continue
1908+
if item.startswith('-'):
1909+
item = item[1:]
1910+
if item in self.annotations:
1911+
continue
1912+
if self.extra and item in self.extra:
1913+
continue
1914+
# names_to_path() validates the lookup. A descriptive
1915+
# FieldError will be raise if it's not.
1916+
self.names_to_path(item.split(LOOKUP_SEP), self.model._meta)
19071917
elif not hasattr(item, 'resolve_expression'):
19081918
errors.append(item)
19091919
if getattr(item, 'contains_aggregate', False):

tests/queries/tests.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3110,20 +3110,13 @@ def test_iter_exceptions(self):
31103110
with self.assertRaisesMessage(AttributeError, msg):
31113111
list(qs)
31123112

3113-
def test_invalid_qs_list(self):
3114-
# Test for #19895 - second iteration over invalid queryset
3115-
# raises errors.
3116-
qs = Article.objects.order_by('invalid_column')
3117-
msg = "Cannot resolve keyword 'invalid_column' into field."
3118-
with self.assertRaisesMessage(FieldError, msg):
3119-
list(qs)
3120-
with self.assertRaisesMessage(FieldError, msg):
3121-
list(qs)
3122-
31233113
def test_invalid_order_by(self):
3124-
msg = "Invalid order_by arguments: ['*']"
3114+
msg = (
3115+
"Cannot resolve keyword '*' into field. Choices are: created, id, "
3116+
"name"
3117+
)
31253118
with self.assertRaisesMessage(FieldError, msg):
3126-
list(Article.objects.order_by('*'))
3119+
Article.objects.order_by('*')
31273120

31283121
def test_invalid_queryset_model(self):
31293122
msg = 'Cannot use QuerySet for "Article": Use a QuerySet for "ExtraInfo".'

0 commit comments

Comments
 (0)