summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham Mahmood <hishammahmood41@gmail.com>2024-02-06 19:40:01 +0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2024-02-07 12:36:30 +0100
commitd79fba7d8e7bbcdf53535a14d57ead5a6863cd8d (patch)
tree1f888d03d2cf1c644acd48f8f2dd573c4341076e
parent6ee37ada3241ed263d8d1c2901b030d964cbd161 (diff)
Fixed #35099 -- Prevented mutating queryset when combining with & and | operators.
Thanks Alan for the report. Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
-rw-r--r--django/db/models/sql/query.py1
-rw-r--r--tests/queries/tests.py18
2 files changed, 19 insertions, 0 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 5100869b34..b3f130c0b4 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -696,6 +696,7 @@ class Query(BaseExpression):
# except if the alias is the base table since it must be present in the
# query on both sides.
initial_alias = self.get_initial_alias()
+ rhs = rhs.clone()
rhs.bump_prefix(self, exclude={initial_alias})
# Work out how to relabel the rhs aliases, if necessary.
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 48d610bb2b..7ac8a65d42 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -1357,6 +1357,24 @@ class Queries1Tests(TestCase):
)
self.assertSequenceEqual(Note.objects.exclude(negate=True), [self.n3])
+ def test_combining_does_not_mutate(self):
+ all_authors = Author.objects.all()
+ authors_with_report = Author.objects.filter(
+ Exists(Report.objects.filter(creator__pk=OuterRef("id")))
+ )
+ authors_without_report = all_authors.exclude(pk__in=authors_with_report)
+ items_before = Item.objects.filter(creator__in=authors_without_report)
+ self.assertCountEqual(items_before, [self.i2, self.i3, self.i4])
+ # Combining querysets doesn't mutate them.
+ all_authors | authors_with_report
+ all_authors & authors_with_report
+
+ authors_without_report = all_authors.exclude(pk__in=authors_with_report)
+ items_after = Item.objects.filter(creator__in=authors_without_report)
+
+ self.assertCountEqual(items_after, [self.i2, self.i3, self.i4])
+ self.assertCountEqual(items_before, items_after)
+
class Queries2Tests(TestCase):
@classmethod