Fixed #27159 -- Prevented pickling a query with an __in=inner_qs lookup from evaluating inner_qs.
This commit is contained in:
parent
78ec4dfeff
commit
7a2c27112d
|
@ -83,6 +83,25 @@ class RelatedIn(In):
|
||||||
else:
|
else:
|
||||||
return super(RelatedIn, self).as_sql(compiler, connection)
|
return super(RelatedIn, self).as_sql(compiler, connection)
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
"""
|
||||||
|
Prevent pickling a query with an __in=inner_qs lookup from evaluating
|
||||||
|
inner_qs.
|
||||||
|
"""
|
||||||
|
from django.db.models.query import QuerySet # Avoid circular import
|
||||||
|
state = self.__dict__.copy()
|
||||||
|
if isinstance(self.rhs, QuerySet):
|
||||||
|
state['rhs'] = (self.rhs.__class__, self.rhs.query)
|
||||||
|
return state
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
self.__dict__.update(state)
|
||||||
|
if isinstance(self.rhs, tuple):
|
||||||
|
queryset_class, query = self.rhs
|
||||||
|
queryset = queryset_class()
|
||||||
|
queryset.query = query
|
||||||
|
self.rhs = queryset
|
||||||
|
|
||||||
|
|
||||||
class RelatedLookupMixin(object):
|
class RelatedLookupMixin(object):
|
||||||
def get_prep_lookup(self):
|
def get_prep_lookup(self):
|
||||||
|
|
|
@ -153,3 +153,42 @@ class PickleabilityTestCase(TestCase):
|
||||||
msg = "Pickled queryset instance's Django version 1.0 does not match the current version %s." % get_version()
|
msg = "Pickled queryset instance's Django version 1.0 does not match the current version %s." % get_version()
|
||||||
with self.assertRaisesMessage(RuntimeWarning, msg):
|
with self.assertRaisesMessage(RuntimeWarning, msg):
|
||||||
pickle.loads(pickle.dumps(qs))
|
pickle.loads(pickle.dumps(qs))
|
||||||
|
|
||||||
|
|
||||||
|
class InLookupTests(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
for i in range(1, 3):
|
||||||
|
group = Group.objects.create(name='Group {}'.format(i))
|
||||||
|
cls.e1 = Event.objects.create(title='Event 1', group=group)
|
||||||
|
|
||||||
|
def test_in_lookup_queryset_evaluation(self):
|
||||||
|
"""
|
||||||
|
Neither pickling nor unpickling a QuerySet.query with an __in=inner_qs
|
||||||
|
lookup should evaluate inner_qs.
|
||||||
|
"""
|
||||||
|
events = Event.objects.filter(group__in=Group.objects.all())
|
||||||
|
|
||||||
|
with self.assertNumQueries(0):
|
||||||
|
dumped = pickle.dumps(events.query)
|
||||||
|
|
||||||
|
with self.assertNumQueries(0):
|
||||||
|
reloaded = pickle.loads(dumped)
|
||||||
|
reloaded_events = Event.objects.none()
|
||||||
|
reloaded_events.query = reloaded
|
||||||
|
|
||||||
|
self.assertSequenceEqual(reloaded_events, [self.e1])
|
||||||
|
|
||||||
|
def test_in_lookup_query_evaluation(self):
|
||||||
|
events = Event.objects.filter(group__in=Group.objects.values('id').query)
|
||||||
|
|
||||||
|
with self.assertNumQueries(0):
|
||||||
|
dumped = pickle.dumps(events.query)
|
||||||
|
|
||||||
|
with self.assertNumQueries(0):
|
||||||
|
reloaded = pickle.loads(dumped)
|
||||||
|
reloaded_events = Event.objects.none()
|
||||||
|
reloaded_events.query = reloaded
|
||||||
|
|
||||||
|
self.assertSequenceEqual(reloaded_events, [self.e1])
|
||||||
|
|
Loading…
Reference in New Issue