Fixed #18590 - Reverted Python 2.4 workaround for Model pickling
Revert of 08d521efa0
. Refs #10547, #12121.
Thanks Michal Petrucha for the report.
This commit is contained in:
parent
1aa0d8ac4d
commit
146aff3bac
|
@ -16,7 +16,7 @@ from django.db.models.fields.related import (ManyToOneRel,
|
||||||
from django.db import (router, transaction, DatabaseError,
|
from django.db import (router, transaction, DatabaseError,
|
||||||
DEFAULT_DB_ALIAS)
|
DEFAULT_DB_ALIAS)
|
||||||
from django.db.models.query import Q
|
from django.db.models.query import Q
|
||||||
from django.db.models.query_utils import DeferredAttribute
|
from django.db.models.query_utils import DeferredAttribute, deferred_class_factory
|
||||||
from django.db.models.deletion import Collector
|
from django.db.models.deletion import Collector
|
||||||
from django.db.models.options import Options
|
from django.db.models.options import Options
|
||||||
from django.db.models import signals
|
from django.db.models import signals
|
||||||
|
@ -400,25 +400,16 @@ class Model(object):
|
||||||
need to do things manually, as they're dynamically created classes and
|
need to do things manually, as they're dynamically created classes and
|
||||||
only module-level classes can be pickled by the default path.
|
only module-level classes can be pickled by the default path.
|
||||||
"""
|
"""
|
||||||
|
if not self._deferred:
|
||||||
|
return super(Model, self).__reduce__()
|
||||||
data = self.__dict__
|
data = self.__dict__
|
||||||
model = self.__class__
|
|
||||||
# The obvious thing to do here is to invoke super().__reduce__()
|
|
||||||
# for the non-deferred case. Don't do that.
|
|
||||||
# On Python 2.4, there is something weird with __reduce__,
|
|
||||||
# and as a result, the super call will cause an infinite recursion.
|
|
||||||
# See #10547 and #12121.
|
|
||||||
defers = []
|
defers = []
|
||||||
if self._deferred:
|
for field in self._meta.fields:
|
||||||
from django.db.models.query_utils import deferred_class_factory
|
if isinstance(self.__class__.__dict__.get(field.attname),
|
||||||
factory = deferred_class_factory
|
DeferredAttribute):
|
||||||
for field in self._meta.fields:
|
defers.append(field.attname)
|
||||||
if isinstance(self.__class__.__dict__.get(field.attname),
|
model = self._meta.proxy_for_model
|
||||||
DeferredAttribute):
|
return (model_unpickle, (model, defers), data)
|
||||||
defers.append(field.attname)
|
|
||||||
model = self._meta.proxy_for_model
|
|
||||||
else:
|
|
||||||
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:
|
||||||
|
@ -926,20 +917,11 @@ def get_absolute_url(opts, func, self, *args, **kwargs):
|
||||||
class Empty(object):
|
class Empty(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def simple_class_factory(model, attrs):
|
def model_unpickle(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.
|
||||||
"""
|
"""
|
||||||
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue