From e044026dce063ec53c16d0f755ec75eb8c84b318 Mon Sep 17 00:00:00 2001 From: Adam Chainz Date: Wed, 16 Nov 2016 14:49:20 +0000 Subject: [PATCH] Fixed #27499 -- Made Prefetches pickle without evaluating their QuerySet. --- django/db/models/query.py | 10 ++++++++++ tests/queryset_pickle/tests.py | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/django/db/models/query.py b/django/db/models/query.py index b6449582b2..9497cb3ce6 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1289,6 +1289,16 @@ class Prefetch(object): self.queryset = queryset self.to_attr = to_attr + def __getstate__(self): + obj_dict = self.__dict__.copy() + if self.queryset is not None: + # Prevent the QuerySet from being evaluated + obj_dict['queryset'] = self.queryset._clone( + _result_cache=[], + _prefetch_done=True, + ) + return obj_dict + def add_prefix(self, prefix): self.prefetch_through = LOOKUP_SEP.join([prefix, self.prefetch_through]) self.prefetch_to = LOOKUP_SEP.join([prefix, self.prefetch_to]) diff --git a/tests/queryset_pickle/tests.py b/tests/queryset_pickle/tests.py index 37069cf286..d95878966a 100644 --- a/tests/queryset_pickle/tests.py +++ b/tests/queryset_pickle/tests.py @@ -134,6 +134,15 @@ class PickleabilityTestCase(TestCase): groups2 = pickle.loads(pickle.dumps(groups)) self.assertSequenceEqual(groups2.filter(id__gte=0), [g]) + def test_pickle_prefetch_queryset_not_evaluated(self): + Group.objects.create(name='foo') + groups = Group.objects.prefetch_related( + models.Prefetch('event_set', queryset=Event.objects.order_by('id')) + ) + list(groups) # evaluate QuerySet + with self.assertNumQueries(0): + pickle.loads(pickle.dumps(groups)) + def test_pickle_prefetch_related_with_m2m_and_objects_deletion(self): """ #24831 -- Cached properties on ManyToOneRel created in QuerySet.delete()