From 820c5f1bacd41713bd30d8b5fefb66752ff15c4c Mon Sep 17 00:00:00 2001 From: Nicolas Delaby Date: Tue, 23 Jan 2024 11:51:24 +0100 Subject: [PATCH] Fixed #35135 -- Made FilteredRelation raise ValueError on querysets as rhs. Regression in 59f475470494ce5b8cbff816b1e5dafcbd10a3a3. --- django/db/models/sql/query.py | 10 ++++++++++ docs/releases/5.0.2.txt | 5 +++++ tests/filtered_relation/tests.py | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 6e8813b5e747..5100869b3429 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -91,6 +91,8 @@ def get_children_from_q(q): def get_child_with_renamed_prefix(prefix, replacement, child): + from django.db.models.query import QuerySet + if isinstance(child, Node): return rename_prefix_from_q(prefix, replacement, child) if isinstance(child, tuple): @@ -105,6 +107,14 @@ def get_child_with_renamed_prefix(prefix, replacement, child): child = child.copy() if child.name.startswith(prefix + LOOKUP_SEP): child.name = child.name.replace(prefix, replacement, 1) + elif isinstance(child, QuerySet): + # QuerySet may contain OuterRef() references which cannot work properly + # without repointing to the filtered annotation and will spawn a + # different JOIN. Always raise ValueError instead of providing partial + # support in other cases. + raise ValueError( + "Passing a QuerySet within a FilteredRelation is not supported." + ) elif hasattr(child, "resolve_expression"): child = child.copy() child.set_source_expressions( diff --git a/docs/releases/5.0.2.txt b/docs/releases/5.0.2.txt index c795049c737a..8e2d648ecce8 100644 --- a/docs/releases/5.0.2.txt +++ b/docs/releases/5.0.2.txt @@ -19,3 +19,8 @@ Bugfixes * Fixed a bug in Django 5.0 that caused a crash of ``Model.full_clean()`` on models with a ``GeneratedField`` (:ticket:`35127`). + +* Fixed a regression in Django 5.0 that caused a crash of + ``FilteredRelation()`` with querysets as right-hand sides (:ticket:`35135`). + ``FilteredRelation()`` now raises a ``ValueError`` on querysets as right-hand + sides. diff --git a/tests/filtered_relation/tests.py b/tests/filtered_relation/tests.py index 19714e844331..82caba866217 100644 --- a/tests/filtered_relation/tests.py +++ b/tests/filtered_relation/tests.py @@ -828,6 +828,16 @@ def test_conditional_expression_lhs_contains_relation_name(self): ).filter(rel__isnull=True) self.assertSequenceEqual(qs, []) + def test_conditional_expression_does_not_support_queryset(self): + msg = "Passing a QuerySet within a FilteredRelation is not supported." + with self.assertRaisesMessage(ValueError, msg): + Author.objects.annotate( + poem_book=FilteredRelation( + "book", + condition=Q(book__in=Book.objects.filter(title__istartswith="a")), + ), + ).filter(poem_book__isnull=False) + class FilteredRelationAggregationTests(TestCase): @classmethod