Last active
September 22, 2016 23:07
-
-
Save LegoStormtroopr/f014801e63474971e7ffc23980f0b1d1 to your computer and use it in GitHub Desktop.
Enable pickling of Django QuerySet with abstract intermediate model
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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