#20257 closed Bug (fixed)
QuerySet that prefetches related object with a ManyToMany field cannot be pickled.
Reported by: | bryced | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.5 |
Severity: | Release blocker | Keywords: | ORM, pickle, cache |
Cc: | bmispelon@… | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
After upgrading from 1.4 to 1.5, exceptions were thrown when trying to pickle certain querysets. This means that the caching framework doesn't work for these querysets.
In 1.4 the following code runs fine. In 1.5 this error occurs:
PicklingError: Can't pickle <class 'people.models.SocialProfile_friends'>: it's not found as people.models.SocialProfile_friends
models.py
from django.db import models class Person(models.Model): name = models.CharField(max_length=200) class SocialProfile(models.Model): person = models.ForeignKey(Person) friends = models.ManyToManyField('self')
tests.py
from django.test import TestCase from people.models import Person import pickle class SimpleTest(TestCase): def test_pickle_failure(self): bob = Person(name="Bob") bob.save() people = Person.objects.all().prefetch_related('socialprofile_set') pickle.dumps(people)
Change History (7)
comment:1 by , 12 years ago
Cc: | added |
---|---|
Component: | Core (Cache system) → Database layer (models, ORM) |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 12 years ago
The problem is that fields for automatic models (for example the intermediary m2m table) can't be pickled in 1.5. In master this is fixed by introducing Field.reduce. In 1.4 the field wasn't used directly, only the field.name was used so there was no problems. So, to fix this, one of the following three things needs to be done:
- alter
QuerySet.__getstate__
and__setstate__
to do something similar that sql.query:Query's state methods do. That is, store the field's name in getstate and restore back the real field instance in setstate. - remove direct storage of the field in QuerySet
- backpatch Field.reduce changes from master
I think the Field.reduce changes are too risky to backpatch, and I assume there was a good reason to store the field directly in QuerySet instead of field.name. So, changes to getstate and setstate seem like the best choice to me.
comment:3 by , 12 years ago
This bug is duplicate of #20157. I've been tracking on it since it is causing me some serious headaches in production since upgrading to 1.5. I do hope for a patch in 1.5.2.
comment:4 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
comment:5 by , 12 years ago
This is currently blocking our team from upgrading to Django 1.5. Just wondering if this will be included in the 1.5.2 release? Thanks for the fix!
comment:6 by , 12 years ago
@michaelmior, Yes it will be. You can see the commit above is prefixed with [1.5.x] indicating it was committed to the stable/1.5.x branch.
comment:7 by , 12 years ago
Thanks @timo! I noticed that after. I apologize if it's bad form to ask, but any ETA on the 1.5.2 release? I'm happy to pitch in if there are release blockers that need to be resolved.
Hi,
Thanks for the detailed report.
I can reproduce the issue in the
stable/1.5.x
branch but it appears to have been fixed inmaster
.The testcase works on the
stable/1.4.x
branch so it is a regression.Using
git bisect
, I found that the problem was introduced by commit 056ace0f395a58eeac03da9f9ee7e3872e1e407b.