Fixed #34012 -- Made QuerySet.order_by() apply transforms on related fields for models with Meta.ordering.

This makes QuerySet.order_by() no longer ignore trailing transforms for
models with Meta.ordering. As a consequence, FieldError is raised in
such cases for non-existent fields.

Thanks to Klaas van Schelven for the report and Mariusz Felisiak for the
review and advice.
This commit is contained in:
David Sanders 2022-09-18 01:44:37 +10:00 committed by Mariusz Felisiak
parent 649b28eab6
commit 4771a1694b
4 changed files with 20 additions and 1 deletions

View File

@ -1001,12 +1001,14 @@ class SQLCompiler:
# If we get to this point and the field is a relation to another model,
# append the default ordering for that model unless it is the pk
# shortcut or the attribute name of the field that is specified.
# shortcut or the attribute name of the field that is specified or
# there are transforms to process.
if (
field.is_relation
and opts.ordering
and getattr(field, "attname", None) != pieces[-1]
and name != "pk"
and not getattr(transform_function, "has_transforms", False)
):
# Firstly, avoid infinite loops.
already_seen = already_seen or set()

View File

@ -1819,6 +1819,7 @@ class Query(BaseExpression):
final_transformer = functools.partial(
transform, name=name, previous=final_transformer
)
final_transformer.has_transforms = True
# Then, add the path to the query's joins. Note that we can't trim
# joins at this stage - we will need the information about join type
# of the trimmed joins.

View File

@ -1,6 +1,7 @@
from datetime import datetime
from operator import attrgetter
from django.core.exceptions import FieldError
from django.db.models import (
CharField,
Count,
@ -91,6 +92,18 @@ class OrderingTests(TestCase):
attrgetter("headline"),
)
def test_default_ordering_override_unknown_field(self):
"""
Attempts to override default ordering on related models with an unknown
field should result in an error.
"""
msg = (
"Cannot resolve keyword 'unknown_field' into field. Choices are: "
"article, author, editor, editor_id, id, name"
)
with self.assertRaisesMessage(FieldError, msg):
list(Article.objects.order_by("author__unknown_field"))
def test_order_by_override(self):
"""
Only the last order_by has any effect (since they each override any

View File

@ -68,6 +68,9 @@ class Annotation(models.Model):
class DateTimePK(models.Model):
date = models.DateTimeField(primary_key=True, default=datetime.datetime.now)
class Meta:
ordering = ["date"]
class ExtraInfo(models.Model):
info = models.CharField(max_length=100)