Skip to content

Commit

Permalink
[2.2.x] Fixed #31863 -- Prevented mutating model state by copies of m…
Browse files Browse the repository at this point in the history
…odel instances.

Regression in bfb746f.

Backport of 94ea79b from master
  • Loading branch information
GertBurger authored and felixxm committed Aug 13, 2020
1 parent 839f906 commit 0a7d321
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
5 changes: 4 additions & 1 deletion django/db/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,10 @@ def __reduce__(self):

def __getstate__(self):
"""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):
msg = None
Expand Down
15 changes: 15 additions & 0 deletions tests/model_regress/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import copy
import datetime
from operator import attrgetter

Expand Down Expand Up @@ -256,3 +257,17 @@ def test_model_with_evaluate_method(self):
dept = Department.objects.create(pk=1, name='abc')
dept.evaluate = 'abc'
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)

0 comments on commit 0a7d321

Please sign in to comment.