diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index c6f080dcbb..7a4cf843c1 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1720,6 +1720,11 @@ class Query(BaseExpression): return target_clause, needed_inner def add_filtered_relation(self, filtered_relation, alias): + if "." in alias: + raise ValueError( + "FilteredRelation doesn't support aliases with periods " + "(got %r)." % alias + ) self.check_alias(alias) filtered_relation.alias = alias relation_lookup_parts, relation_field_parts, _ = self.solve_lookup_type( diff --git a/tests/filtered_relation/tests.py b/tests/filtered_relation/tests.py index cdcd5c19af..e263307193 100644 --- a/tests/filtered_relation/tests.py +++ b/tests/filtered_relation/tests.py @@ -216,6 +216,19 @@ class FilteredRelationTests(TestCase): str(queryset.query), ) + def test_period_forbidden(self): + msg = ( + "FilteredRelation doesn't support aliases with periods (got 'book.alice')." + ) + with self.assertRaisesMessage(ValueError, msg): + Author.objects.annotate( + **{ + "book.alice": FilteredRelation( + "book", condition=Q(book__title__iexact="poem by alice") + ) + } + ) + def test_multiple(self): qs = ( Author.objects.annotate( diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py index afe2e3c22c..008f0239b3 100644 --- a/tests/ordering/tests.py +++ b/tests/ordering/tests.py @@ -18,7 +18,6 @@ from django.db.models import ( When, ) from django.db.models.functions import Length, Upper -from django.db.utils import DatabaseError from django.test import TestCase from .models import ( @@ -411,13 +410,19 @@ class OrderingTests(TestCase): self.assertNotEqual(qs[0].headline, "Backdated") relation = FilteredRelation("author") - qs2 = Article.objects.annotate(**{crafted: relation}).order_by(crafted) - with self.assertRaises(DatabaseError): + msg = ( + "FilteredRelation doesn't support aliases with periods " + "(got 'ordering_article.pub_date')." + ) + with self.assertRaisesMessage(ValueError, msg): + qs2 = Article.objects.annotate(**{crafted: relation}).order_by(crafted) # Before, unlike F(), which causes ordering expressions to be # replaced by ordinals like n in ORDER BY n, these were ordered by # pub_date instead of author. # The Article model orders by -pk, so sorting on author will place # first any article by author2 instead of the backdated one. + # This assertion is reachable if FilteredRelation.__init__() starts + # supporting periods in aliases in the future. self.assertNotEqual(qs2[0].headline, "Backdated") def test_order_by_pk(self):