summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGert Burger <gertburger@gmail.com>2020-08-07 10:02:29 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-08-13 15:27:52 +0200
commitc33b6ceff4c3462dec8555e395c6f45faa61c490 (patch)
tree06882d688df58754831283e70e9b7fc348636133
parent784ed4ada112753c35dd7c6b85686ad1d935b65d (diff)
downloaddjango-c33b6ceff4c3462dec8555e395c6f45faa61c490.tar.gz
[3.0.x] Fixed #31863 -- Prevented mutating model state by copies of model instances.
Regression in bfb746f983aa741afa3709794e70f1e0ab6040b5. Backport of 94ea79be137f3cb30949bf82198e96e094f2650d from master
-rw-r--r--django/db/models/base.py5
-rw-r--r--tests/model_regress/tests.py15
2 files changed, 19 insertions, 1 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 63801da3c2..814e6ee280 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -543,7 +543,10 @@ class Model(metaclass=ModelBase):
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
diff --git a/tests/model_regress/tests.py b/tests/model_regress/tests.py
index 28eed87008..87df240d81 100644
--- a/tests/model_regress/tests.py
+++ b/tests/model_regress/tests.py
@@ -1,3 +1,4 @@
+import copy
import datetime
from operator import attrgetter
@@ -256,3 +257,17 @@ class EvaluateMethodTest(TestCase):
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)