diff --git a/modeltranslation/manager.py b/modeltranslation/manager.py index 7f9e216..fee8ba9 100644 --- a/modeltranslation/manager.py +++ b/modeltranslation/manager.py @@ -171,6 +171,9 @@ class MultilingualQuerySet(models.query.QuerySet): ordering.append(rewrite_order_lookup_key(self.model, key)) self.query.add_ordering(*ordering) + def __reduce__(self): + return multilingual_queryset_factory, (self.__class__.__bases__[0],), self.__getstate__() + # This method was not present in django-linguo def _clone(self, klass=None, *args, **kwargs): if klass is not None and not issubclass(klass, MultilingualQuerySet): @@ -445,6 +448,16 @@ def get_queryset(obj): return obj.get_query_set() +def multilingual_queryset_factory(old_cls, instantiate=True): + if old_cls == models.query.QuerySet: + NewClass = MultilingualQuerySet + else: + class NewClass(old_cls, MultilingualQuerySet): + pass + NewClass.__name__ = 'Multilingual%s' % old_cls.__name__ + return NewClass() if instantiate else NewClass + + class MultilingualQuerysetManager(models.Manager): """ This class gets hooked in MRO just before plain Manager, so that every call to @@ -455,13 +468,7 @@ class MultilingualQuerysetManager(models.Manager): return self._patch_queryset(qs) def _patch_queryset(self, qs): - if qs.__class__ == models.query.QuerySet: - qs.__class__ = MultilingualQuerySet - else: - class NewClass(qs.__class__, MultilingualQuerySet): - pass - NewClass.__name__ = 'Multilingual%s' % qs.__class__.__name__ - qs.__class__ = NewClass + qs.__class__ = multilingual_queryset_factory(qs.__class__, instantiate=False) qs._post_init() qs._rewrite_applied_operations() return qs diff --git a/modeltranslation/tests/tests.py b/modeltranslation/tests/tests.py index e8d3ffa..863e841 100644 --- a/modeltranslation/tests/tests.py +++ b/modeltranslation/tests/tests.py @@ -2564,6 +2564,27 @@ class TestManager(ModeltranslationTestBase): qs = models.CustomManagerTestModel.objects.custom_qs() self.assertIsInstance(qs, MultilingualQuerySet) + def test_multilingual_queryset_pickling(self): + import pickle + from modeltranslation.manager import MultilingualQuerySet + + # typical + models.CustomManagerTestModel.objects.create(title='a') + qs = models.CustomManagerTestModel.objects.all() + serialized = pickle.dumps(qs) + deserialized = pickle.loads(serialized) + self.assertIsInstance(deserialized, MultilingualQuerySet) + self.assertListEqual(list(qs), list(deserialized)) + + # Generated class + models.CustomManager2TestModel.objects.create() + qs = models.CustomManager2TestModel.objects.all() + serialized = pickle.dumps(qs) + deserialized = pickle.loads(serialized) + self.assertIsInstance(deserialized, MultilingualQuerySet) + self.assertIsInstance(deserialized, models.CustomQuerySet) + self.assertListEqual(list(qs), list(deserialized)) + def test_non_objects_manager(self): """Test if managers other than ``objects`` are patched too""" from modeltranslation.manager import MultilingualManager