Fixed #11082 -- Ensured that subqueries used in an exclude(X__in=) clause aren't pre-evaluated. Thanks to Henry Andrews for the report, and clement for the fix.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10929 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2009-06-06 13:35:33 +00:00
parent fa43a32bcb
commit 151d88af4e
3 changed files with 45 additions and 1 deletions

View File

@ -7,6 +7,8 @@ try:
except NameError: except NameError:
from sets import Set as set # Python 2.3 fallback from sets import Set as set # Python 2.3 fallback
from copy import deepcopy
from django.db import connection, transaction, IntegrityError from django.db import connection, transaction, IntegrityError
from django.db.models.aggregates import Aggregate from django.db.models.aggregates import Aggregate
from django.db.models.fields import DateField from django.db.models.fields import DateField
@ -40,6 +42,17 @@ class QuerySet(object):
# PYTHON MAGIC METHODS # # PYTHON MAGIC METHODS #
######################## ########################
def __deepcopy__(self, memo):
"""
Deep copy of a QuerySet doesn't populate the cache
"""
obj_dict = deepcopy(self.__dict__, memo)
obj_dict['_iter'] = None
obj = self.__class__()
obj.__dict__.update(obj_dict)
return obj
def __getstate__(self): def __getstate__(self):
""" """
Allows the QuerySet to be pickled. Allows the QuerySet to be pickled.

View File

@ -1625,10 +1625,14 @@ class BaseQuery(object):
entry.negate() entry.negate()
self.where.add(entry, AND) self.where.add(entry, AND)
break break
elif not (lookup_type == 'in' and not value) and field.null: elif not (lookup_type == 'in'
and not hasattr(value, 'as_sql')
and not hasattr(value, '_as_sql')
and not value) and field.null:
# Leaky abstraction artifact: We have to specifically # Leaky abstraction artifact: We have to specifically
# exclude the "foo__in=[]" case from this handling, because # exclude the "foo__in=[]" case from this handling, because
# it's short-circuited in the Where class. # it's short-circuited in the Where class.
# We also need to handle the case where a subquery is provided
entry = self.where_class() entry = self.where_class()
entry.add((Constraint(alias, col, None), 'isnull', True), AND) entry.add((Constraint(alias, col, None), 'isnull', True), AND)
entry.negate() entry.negate()

View File

@ -1143,6 +1143,33 @@ True
>>> r.save() >>> r.save()
>>> Ranking.objects.all() >>> Ranking.objects.all()
[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>] [<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
# Regression test for #10742:
# Queries used in an __in clause don't execute subqueries
>>> subq = Author.objects.filter(num__lt=3000)
>>> qs = Author.objects.filter(pk__in=subq)
>>> list(qs)
[<Author: a1>, <Author: a2>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
>>> subq = Author.objects.filter(num__lt=3000)
>>> qs = Author.objects.exclude(pk__in=subq)
>>> list(qs)
[<Author: a3>, <Author: a4>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
>>> subq = Author.objects.filter(num__lt=3000)
>>> list(Author.objects.filter(Q(pk__in=subq) & Q(name='a1')))
[<Author: a1>]
# The subquery result cache should not be populated
>>> subq._result_cache is None
True
"""} """}
# In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__ # In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__