From 4771a1694b3b54c7309602820881d3ec9cc2c809 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Sun, 18 Sep 2022 01:44:37 +1000 Subject: [PATCH] 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. --- django/db/models/sql/compiler.py | 4 +++- django/db/models/sql/query.py | 1 + tests/ordering/tests.py | 13 +++++++++++++ tests/queries/models.py | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index c7efa469a8..4f2783a635 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -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() diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 12cb390e98..61e39b5153 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -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. diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py index e4f7d75992..8109ea1b45 100644 --- a/tests/ordering/tests.py +++ b/tests/ordering/tests.py @@ -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 diff --git a/tests/queries/models.py b/tests/queries/models.py index 0e8d6dd174..23c41e3374 100644 --- a/tests/queries/models.py +++ b/tests/queries/models.py @@ -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)