summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2021-09-30 11:26:17 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-09-30 11:26:53 +0200
commit93a42d43a6995993b9bbcb743ab3c2a2b8414ebd (patch)
tree1b4df989f52b02666c2bc766f990e59712935aa1
parentb2a0978610413e4cd5ebb716b8bfa7803dff8d5b (diff)
[4.0.x] Fixed #33159 -- Reverted "Fixed #32970 -- Changed WhereNode.clone() to create a shallow copy of children."
This reverts commit e441847ecae99dd1ccd0d9ce76dbcff51afa863c. A shallow copy is not enough because querysets can be reused and evaluated in nested nodes, which shouldn't mutate JOIN aliases. Thanks Michal Čihař for the report. Backport of 903aaa35e5ceaa33bfc9b19b7f6da65ce5a91dd4 from main
-rw-r--r--django/db/models/sql/where.py6
-rw-r--r--tests/queries/tests.py6
2 files changed, 11 insertions, 1 deletions
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 160d5733b8..50ff13be75 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -148,7 +148,11 @@ class WhereNode(tree.Node):
clone = self.__class__._new_instance(
children=None, connector=self.connector, negated=self.negated,
)
- clone.children = self.children[:]
+ for child in self.children:
+ if hasattr(child, 'clone'):
+ clone.children.append(child.clone())
+ else:
+ clone.children.append(child)
return clone
def relabeled_clone(self, change_map):
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index fa87e7859c..9c1b41a395 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -1663,6 +1663,12 @@ class Queries5Tests(TestCase):
'bar %s'
)
+ def test_queryset_reuse(self):
+ # Using querysets doesn't mutate aliases.
+ authors = Author.objects.filter(Q(name='a1') | Q(name='nonexistent'))
+ self.assertEqual(Ranking.objects.filter(author__in=authors).get(), self.rank3)
+ self.assertEqual(authors.count(), 1)
+
class SelectRelatedTests(TestCase):
def test_tickets_3045_3288(self):