Skip to content

Instantly share code, notes, and snippets.

@LegoStormtroopr
Last active September 22, 2016 23:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LegoStormtroopr/f014801e63474971e7ffc23980f0b1d1 to your computer and use it in GitHub Desktop.
Save LegoStormtroopr/f014801e63474971e7ffc23980f0b1d1 to your computer and use it in GitHub Desktop.
Enable pickling of Django QuerySet with abstract intermediate model
import copy_reg
from django.db.models.fields import Field, _load_field, _empty
def _load_field_for_abstract(model, field_name):
return model._meta.get_field(field_name)
def pickle_abstract_field(field):
"""
Pickling should return the model._meta.fields instance of the field,
not a new copy of that field. So, we use the app registry to load the
model and then the field back.
"""
self = field
if not hasattr(self, 'model'):
# Fields are sometimes used without attaching them to models (for
# example in aggregation). In this case give back a plain field
# instance. The code below will create a new empty instance of
# class self.__class__, then update its dict with self.__dict__
# values - so, this is very close to normal pickle.
return _empty, (self.__class__,), self.__dict__
if self.model._deferred:
# Deferred model will not be found from the app registry. This
# could be fixed by reconstructing the deferred model on unpickle.
raise RuntimeError("Fields of deferred models can't be reduced")
if self.model._meta.abstract:
func = _load_field_for_abstract
args = (
self.model,
self.name
)
else:
func = _load_field
args = (
self.model._meta.app_label, self.model._meta.object_name,
self.name
)
return func, args
copy_reg.pickle(Field, pickle_abstract_field)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment