[3.1.x] Fixed #31863 -- Prevented mutating model state by copies of model instances.

Regression in bfb746f983.

Backport of 94ea79be13 from master
This commit is contained in:
Gert Burger 2020-08-07 10:02:29 +02:00 committed by Mariusz Felisiak
parent 9ae40d8137
commit 85c47b9a73
2 changed files with 19 additions and 1 deletions

View File

@ -544,7 +544,10 @@ class Model(metaclass=ModelBase):
def __getstate__(self): def __getstate__(self):
"""Hook to allow choosing the attributes to pickle.""" """Hook to allow choosing the attributes to pickle."""
return self.__dict__ state = self.__dict__.copy()
state['_state'] = copy.copy(state['_state'])
state['_state'].fields_cache = state['_state'].fields_cache.copy()
return state
def __setstate__(self, state): def __setstate__(self, state):
pickled_version = state.get(DJANGO_VERSION_PICKLE_KEY) pickled_version = state.get(DJANGO_VERSION_PICKLE_KEY)

View File

@ -1,3 +1,4 @@
import copy
import datetime import datetime
from operator import attrgetter from operator import attrgetter
@ -256,3 +257,17 @@ class EvaluateMethodTest(TestCase):
dept = Department.objects.create(pk=1, name='abc') dept = Department.objects.create(pk=1, name='abc')
dept.evaluate = 'abc' dept.evaluate = 'abc'
Worker.objects.filter(department=dept) Worker.objects.filter(department=dept)
class ModelFieldsCacheTest(TestCase):
def test_fields_cache_reset_on_copy(self):
department1 = Department.objects.create(id=1, name='department1')
department2 = Department.objects.create(id=2, name='department2')
worker1 = Worker.objects.create(name='worker', department=department1)
worker2 = copy.copy(worker1)
self.assertEqual(worker2.department, department1)
# Changing related fields doesn't mutate the base object.
worker2.department = department2
self.assertEqual(worker2.department, department2)
self.assertEqual(worker1.department, department1)