Skip to content

Commit 97cb3bd

Browse files
Nerlintimgraham
authored andcommitted
Fixed #28456 -- Allowed customizing Model pickling by overriding __getstate__().
1 parent 31f133e commit 97cb3bd

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

django/db/models/base.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,11 +522,15 @@ def __hash__(self):
522522
return hash(self.pk)
523523

524524
def __reduce__(self):
525-
data = self.__dict__
525+
data = self.__getstate__()
526526
data[DJANGO_VERSION_PICKLE_KEY] = get_version()
527527
class_id = self._meta.app_label, self._meta.object_name
528528
return model_unpickle, (class_id,), data
529529

530+
def __getstate__(self):
531+
"""Hook to allow choosing the attributes to pickle."""
532+
return self.__dict__
533+
530534
def __setstate__(self, state):
531535
msg = None
532536
pickled_version = state.get(DJANGO_VERSION_PICKLE_KEY)

tests/model_regress/test_pickle.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,20 @@ def __reduce__(self):
4343
msg = "Pickled model instance's Django version 1.0 does not match the current version %s." % get_version()
4444
with self.assertRaisesMessage(RuntimeWarning, msg):
4545
pickle.loads(pickle.dumps(p))
46+
47+
def test_with_getstate(self):
48+
"""
49+
A model may override __getstate__() to choose the attributes to pickle.
50+
"""
51+
class PickledModel(models.Model):
52+
def __getstate__(self):
53+
state = super().__getstate__().copy()
54+
del state['dont_pickle']
55+
return state
56+
57+
m = PickledModel()
58+
m.dont_pickle = 1
59+
dumped = pickle.dumps(m)
60+
self.assertEqual(m.dont_pickle, 1)
61+
reloaded = pickle.loads(dumped)
62+
self.assertFalse(hasattr(reloaded, 'dont_pickle'))

0 commit comments

Comments
 (0)