summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <simon.charette@zapier.com>2019-09-23 15:51:43 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-09-24 09:47:21 +0200
commit6b7bd079a6fc4e84553262b65074dbe0af456b03 (patch)
treedfff4f1b709b7f97786ecab8b5b5b867f83a221a
parent9510af35fce9de740f76f04cb5216c42daa1b9f3 (diff)
[3.0.x] Fixed #30796 -- Prevented select_related() from mutating a queryset on chaining.
Thanks Darren Maki for the report. Backport of 37f8f293775d0b672da8ae369d9a4e17f1db7851 from master
-rw-r--r--django/db/models/sql/query.py5
-rw-r--r--tests/queries/test_query.py7
2 files changed, 12 insertions, 0 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 8e55bd092d..ea51912e8b 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -6,6 +6,7 @@ themselves do not have to (and could be backed by things other than SQL
databases). The abstraction barrier only works one way: this module has to know
all about the internals of models in order to get the information it needs.
"""
+import copy
import difflib
import functools
import inspect
@@ -324,6 +325,10 @@ class Query(BaseExpression):
obj._extra_select_cache = None
else:
obj._extra_select_cache = self._extra_select_cache.copy()
+ if self.select_related is not False:
+ # Use deepcopy because select_related stores fields in nested
+ # dicts.
+ obj.select_related = copy.deepcopy(obj.select_related)
if 'subq_aliases' in self.__dict__:
obj.subq_aliases = self.subq_aliases.copy()
obj.used_aliases = self.used_aliases.copy()
diff --git a/tests/queries/test_query.py b/tests/queries/test_query.py
index c6a659fe97..f0d3a6260a 100644
--- a/tests/queries/test_query.py
+++ b/tests/queries/test_query.py
@@ -106,3 +106,10 @@ class TestQuery(SimpleTestCase):
self.assertIsInstance(b_isnull, RelatedIsNull)
self.assertIsInstance(b_isnull.lhs, SimpleCol)
self.assertEqual(b_isnull.lhs.target, ObjectC._meta.get_field('objectb'))
+
+ def test_clone_select_related(self):
+ query = Query(Item)
+ query.add_select_related(['creator'])
+ clone = query.clone()
+ clone.add_select_related(['note', 'creator__extra'])
+ self.assertEqual(query.select_related, {'creator': {}})