mirror of https://github.com/django/django.git
Fixed #12163 -- Corrected the unpickling of non-deferred models. Thanks to rfugger for the report and test case.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11732 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
3f8f3f8411
commit
632f12fba4
|
@ -361,6 +361,8 @@ class Model(object):
|
||||||
defers = []
|
defers = []
|
||||||
pk_val = None
|
pk_val = None
|
||||||
if self._deferred:
|
if self._deferred:
|
||||||
|
from django.db.models.query_utils import deferred_class_factory
|
||||||
|
factory = deferred_class_factory
|
||||||
for field in self._meta.fields:
|
for field in self._meta.fields:
|
||||||
if isinstance(self.__class__.__dict__.get(field.attname),
|
if isinstance(self.__class__.__dict__.get(field.attname),
|
||||||
DeferredAttribute):
|
DeferredAttribute):
|
||||||
|
@ -371,8 +373,9 @@ class Model(object):
|
||||||
# once.
|
# once.
|
||||||
obj = self.__class__.__dict__[field.attname]
|
obj = self.__class__.__dict__[field.attname]
|
||||||
model = obj.model_ref()
|
model = obj.model_ref()
|
||||||
|
else:
|
||||||
return (model_unpickle, (model, defers), data)
|
factory = simple_class_factory
|
||||||
|
return (model_unpickle, (model, defers, factory), data)
|
||||||
|
|
||||||
def _get_pk_val(self, meta=None):
|
def _get_pk_val(self, meta=None):
|
||||||
if not meta:
|
if not meta:
|
||||||
|
@ -657,12 +660,20 @@ def get_absolute_url(opts, func, self, *args, **kwargs):
|
||||||
class Empty(object):
|
class Empty(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def model_unpickle(model, attrs):
|
def simple_class_factory(model, attrs):
|
||||||
|
"""Used to unpickle Models without deferred fields.
|
||||||
|
|
||||||
|
We need to do this the hard way, rather than just using
|
||||||
|
the default __reduce__ implementation, because of a
|
||||||
|
__deepcopy__ problem in Python 2.4
|
||||||
|
"""
|
||||||
|
return model
|
||||||
|
|
||||||
|
def model_unpickle(model, attrs, factory):
|
||||||
"""
|
"""
|
||||||
Used to unpickle Model subclasses with deferred fields.
|
Used to unpickle Model subclasses with deferred fields.
|
||||||
"""
|
"""
|
||||||
from django.db.models.query_utils import deferred_class_factory
|
cls = factory(model, attrs)
|
||||||
cls = deferred_class_factory(model, attrs)
|
|
||||||
return cls.__new__(cls)
|
return cls.__new__(cls)
|
||||||
model_unpickle.__safe_for_unpickle__ = True
|
model_unpickle.__safe_for_unpickle__ = True
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,23 @@ u'c1'
|
||||||
>>> results[0].second_child.name
|
>>> results[0].second_child.name
|
||||||
u'c2'
|
u'c2'
|
||||||
|
|
||||||
|
# Test for #12163 - Pickling error saving session with unsaved model instances.
|
||||||
|
>>> from django.contrib.sessions.backends.db import SessionStore
|
||||||
|
>>> SESSION_KEY = '2b1189a188b44ad18c35e1baac6ceead'
|
||||||
|
>>> item = Item()
|
||||||
|
>>> item._deferred
|
||||||
|
False
|
||||||
|
>>> s = SessionStore(SESSION_KEY)
|
||||||
|
>>> s.clear()
|
||||||
|
>>> s['item'] = item
|
||||||
|
>>> s.save()
|
||||||
|
>>> s = SessionStore(SESSION_KEY)
|
||||||
|
>>> s.modified = True
|
||||||
|
>>> s.save()
|
||||||
|
>>> i2 = s['item']
|
||||||
|
>>> i2._deferred # Item must still be non-deferred
|
||||||
|
False
|
||||||
|
|
||||||
# Finally, we need to flush the app cache for the defer module.
|
# Finally, we need to flush the app cache for the defer module.
|
||||||
# Using only/defer creates some artifical entries in the app cache
|
# Using only/defer creates some artifical entries in the app cache
|
||||||
# that messes up later tests. Purge all entries, just to be sure.
|
# that messes up later tests. Purge all entries, just to be sure.
|
||||||
|
|
Loading…
Reference in New Issue