Skip to content

Commit 05e4d51

Browse files
committed
queryset-refactor: Simplify the way filters are passed to the Query class.
This removes a lot of the complexity for handling exclude() calls and results in more efficient code. I feel a bit stupid for not having spotted this earlier. git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7461 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent fcc3648 commit 05e4d51

File tree

3 files changed

+14
-35
lines changed

3 files changed

+14
-35
lines changed

django/db/models/query.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.conf import settings
44
from django.db import connection, transaction, IntegrityError
55
from django.db.models.fields import DateField, FieldDoesNotExist
6-
from django.db.models.query_utils import Q, not_q
6+
from django.db.models.query_utils import Q
77
from django.db.models import signals, sql
88
from django.dispatch import dispatcher
99
from django.utils.datastructures import SortedDict
@@ -355,29 +355,25 @@ def filter(self, *args, **kwargs):
355355
Returns a new QuerySet instance with the args ANDed to the existing
356356
set.
357357
"""
358-
return self._filter_or_exclude(None, *args, **kwargs)
358+
return self._filter_or_exclude(False, *args, **kwargs)
359359

360360
def exclude(self, *args, **kwargs):
361361
"""
362362
Returns a new QuerySet instance with NOT (args) ANDed to the existing
363363
set.
364364
"""
365-
return self._filter_or_exclude(not_q, *args, **kwargs)
365+
return self._filter_or_exclude(True, *args, **kwargs)
366366

367-
def _filter_or_exclude(self, mapper, *args, **kwargs):
368-
# mapper is a callable used to transform Q objects,
369-
# or None for identity transform.
370-
if mapper is None:
371-
mapper = lambda x: x
367+
def _filter_or_exclude(self, negate, *args, **kwargs):
372368
if args or kwargs:
373369
assert self.query.can_filter(), \
374-
"Cannot filter a query once a slice has been taken."
370+
"Cannot filter a query once a slice has been taken."
375371

376372
clone = self._clone()
377-
if kwargs:
378-
clone.query.add_q(mapper(Q(**kwargs)))
379-
for arg in args:
380-
clone.query.add_q(mapper(arg))
373+
if negate:
374+
clone.query.add_q(~Q(*args, **kwargs))
375+
else:
376+
clone.query.add_q(Q(*args, **kwargs))
381377
return clone
382378

383379
def complex_filter(self, filter_obj):

django/db/models/query_utils.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ class Q(tree.Node):
2828
default = AND
2929

3030
def __init__(self, *args, **kwargs):
31-
if args and kwargs:
32-
raise TypeError('Use positional *or* kwargs; not both!')
33-
nodes = list(args) + kwargs.items()
34-
super(Q, self).__init__(children=nodes)
31+
super(Q, self).__init__(children=list(args) + kwargs.items())
3532

3633
def _combine(self, other, conn):
3734
if not isinstance(other, Q):
@@ -51,6 +48,3 @@ def __invert__(self):
5148
obj.negate()
5249
return obj
5350

54-
def not_q(q):
55-
return ~q
56-

django/db/models/sql/query.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -969,24 +969,11 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
969969
# that's harmless.
970970
self.promote_alias(table)
971971

972-
entry = (alias, col, field, lookup_type, value)
973-
if negate and single_filter:
974-
# This case is when we're doing the Q2 filter in exclude(Q1, Q2).
975-
# It's different from exclude(Q1).exclude(Q2).
976-
for node in self.where.children:
977-
if getattr(node, 'negated', False):
978-
node.add(entry, connector)
979-
merged = True
980-
break
981-
else:
982-
self.where.add(entry, connector)
983-
merged = False
984-
972+
self.where.add((alias, col, field, lookup_type, value), connector)
985973
if negate:
974+
self.where.negate()
986975
for alias in join_list:
987976
self.promote_alias(alias)
988-
if not merged:
989-
self.where.negate()
990977
if final > 1 and lookup_type != 'isnull':
991978
for alias in join_list:
992979
if self.alias_map[alias] == self.LOUTER:
@@ -1019,6 +1006,8 @@ def add_q(self, q_object):
10191006
self.where.start_subtree(connector)
10201007
self.add_q(child)
10211008
self.where.end_subtree()
1009+
if q_object.negated:
1010+
self.where.children[-1].negate()
10221011
else:
10231012
self.add_filter(child, connector, q_object.negated,
10241013
single_filter=internal)

0 commit comments

Comments
 (0)