Skip to content

Commit

Permalink
Fixed #11082 -- Ensured that subqueries used in an exclude(X__in=) cl…
Browse files Browse the repository at this point in the history
…ause 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
  • Loading branch information
freakboy3742 committed Jun 6, 2009
1 parent fa43a32 commit 151d88a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 1 deletion.
13 changes: 13 additions & 0 deletions django/db/models/query.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
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
Expand Down Expand Up @@ -40,6 +42,17 @@ def __init__(self, model=None, query=None):
# 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.
Expand Down
6 changes: 5 additions & 1 deletion django/db/models/sql/query.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1625,10 +1625,14 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
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()
Expand Down
27 changes: 27 additions & 0 deletions tests/regressiontests/queries/models.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1143,6 +1143,33 @@ def __unicode__(self):
>>> 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__
Expand Down

0 comments on commit 151d88a

Please sign in to comment.