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:
|
||||
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):
|
||||
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()
|
||||
with self.assertRaisesMessage(RuntimeWarning, msg):
|
||||
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