#25389 closed Bug (fixed)
SimpleLazyObject doesn't pickle correctly when wrapping a Model
| Reported by: | Ben Kraft | Owned by: | Ben Kraft |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.8 |
| Severity: | Release blocker | Keywords: | |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Given a SimpleLazyObject wrapping an instance of a Django model, if the SimpleLazyObject has not yet been initialized, pickling it will not correctly save the _django_version attribute added by 42736ac8. This happens because SimpleLazyObject's overridden __reduce_ex__ clobbers that of Model, and means that unpickling the pickled object will raise a warning. An example is given here. This is especially relevant given that request.user is a SimpleLazyObject wrapping a model instance, so this will happen when pickling an untouched request.user.
Furthermore, pickling a SimpleLazyObject wrapping a class which does certain scary things to its __dict__ and overrides __reduce__ can cause an error while pickling. An abstract example is given here. (I don't think that supporting this case is a necessity, but it was how I noticed the above issue, and the attached patch fixes both cases.)
Currently the behavior is effectively to just initialize and then pickle the wrapped object. I have and will attach a patch which does that in a more direct way that works in both of the above cases. It also adds a regression test which covers both of the above cases.
Change History (10)
comment:1 by , 10 years ago
| Has patch: | set |
|---|---|
| Status: | new → assigned |
comment:2 by , 10 years ago
| Component: | Uncategorized → Database layer (models, ORM) |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
comment:3 by , 10 years ago
For what it's worth, I've now realized that you don't actually need to do terrifying things to __dict__ to get the actual error; you just have to keep a reference to a model instance as a property on the instance. I've added an example to the gist here; again Foo here simulates a model. In any case, the fix still works.
comment:4 by , 10 years ago
| Severity: | Normal → Release blocker |
|---|
This is a regression in 1.8 according to #25426.
comment:6 by , 10 years ago
| Patch needs improvement: | unset |
|---|
comment:7 by , 10 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Pending some cosmetic tweaks.
Patch is in https://github.com/django/django/pull/5276. I ran
utils_tests.test_lazyobjectin both python 2 and python 3.