Fixed #30796 -- Prevented select_related() from mutating a queryset on chaining.

Thanks Darren Maki for the report.
This commit is contained in:
Simon Charette 2019-09-23 15:51:43 -04:00 committed by Mariusz Felisiak
parent e8ad265ac8
commit 37f8f29377
2 changed files with 12 additions and 0 deletions

View File

@ -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()

View File

@ -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': {}})