Skip to content

Commit

Permalink
[3.0.x] Fixed #30796 -- Prevented select_related() from mutating a qu…
Browse files Browse the repository at this point in the history
…eryset on chaining.

Thanks Darren Maki for the report.

Backport of 37f8f29 from master
  • Loading branch information
charettes authored and felixxm committed Sep 24, 2019
1 parent 9510af3 commit 6b7bd07
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 0 deletions.
5 changes: 5 additions & 0 deletions django/db/models/sql/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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
Expand Down Expand Up @@ -324,6 +325,10 @@ def clone(self):
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()
Expand Down
7 changes: 7 additions & 0 deletions tests/queries/test_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,10 @@ def test_foreign_key_exclusive(self):
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': {}})

0 comments on commit 6b7bd07

Please sign in to comment.