1
0
mirror of https://github.com/django/django.git synced 2025-06-05 03:29:12 +00:00

[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
This commit is contained in:
Simon Charette 2019-09-23 15:51:43 -04:00 committed by Mariusz Felisiak
parent 9510af35fc
commit 6b7bd079a6
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 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. all about the internals of models in order to get the information it needs.
""" """
import copy
import difflib import difflib
import functools import functools
import inspect import inspect
@ -324,6 +325,10 @@ class Query(BaseExpression):
obj._extra_select_cache = None obj._extra_select_cache = None
else: else:
obj._extra_select_cache = self._extra_select_cache.copy() 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__: if 'subq_aliases' in self.__dict__:
obj.subq_aliases = self.subq_aliases.copy() obj.subq_aliases = self.subq_aliases.copy()
obj.used_aliases = self.used_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, RelatedIsNull)
self.assertIsInstance(b_isnull.lhs, SimpleCol) self.assertIsInstance(b_isnull.lhs, SimpleCol)
self.assertEqual(b_isnull.lhs.target, ObjectC._meta.get_field('objectb')) 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': {}})