1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

queryset-refactor: Fixed a few really silly errors in the Q class and negation

handling in the tree class. Discovered whilst starting to fix exclude().


git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7169 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-02-28 02:49:31 +00:00
parent c8afb75d53
commit 0588dee34c
4 changed files with 45 additions and 45 deletions

View File

@ -2,7 +2,7 @@ import warnings
from django.db import connection, transaction
from django.db.models.fields import DateField, FieldDoesNotExist
from django.db.models.query_utils import Q, QNot, EmptyResultSet
from django.db.models.query_utils import Q, EmptyResultSet, not_q
from django.db.models import signals, sql
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
@ -316,7 +316,7 @@ class _QuerySet(object):
Returns a new QuerySet instance with NOT (args) ANDed to the existing
set.
"""
return self._filter_or_exclude(QNot, *args, **kwargs)
return self._filter_or_exclude(not_q, *args, **kwargs)
def _filter_or_exclude(self, mapper, *args, **kwargs):
# mapper is a callable used to transform Q objects,
@ -591,15 +591,20 @@ class EmptyQuerySet(QuerySet):
# (it raises StopIteration immediately).
yield iter([]).next()
# QOperator, QAnd and QOr are temporarily retained for backwards compatibility.
# All the old functionality is now part of the 'Q' class.
# QOperator, QNot, QAnd and QOr are temporarily retained for backwards
# compatibility. All the old functionality is now part of the 'Q' class.
class QOperator(Q):
def __init__(self, *args, **kwargs):
warnings.warn('Use Q instead of QOr, QAnd or QOperation.',
DeprecationWarning, stacklevel=2)
super(QOperator, self).__init__(*args, **kwargs)
QOr = QAnd = QOperator
def QNot(q):
warnings.warn('Use ~q instead of QNot(q)', DeprecationWarning, stacklevel=2)
return ~q
def get_cached_row(klass, row, index_start, max_depth=0, cur_depth=0,
requested=None):
"""Helper function that recursively returns an object with cache filled"""

View File

@ -4,6 +4,9 @@ Various data structures used in query construction.
Factored out from django.db.models.query so that they can also be used by other
modules without getting into circular import difficulties.
"""
from copy import deepcopy
from django.utils import tree
class EmptyResultSet(Exception):
@ -31,8 +34,9 @@ class Q(tree.Node):
def _combine(self, other, conn):
if not isinstance(other, Q):
raise TypeError(other)
self.add(other, conn)
return self
obj = deepcopy(self)
obj.add(other, conn)
return obj
def __or__(self, other):
return self._combine(other, self.OR)
@ -41,18 +45,10 @@ class Q(tree.Node):
return self._combine(other, self.AND)
def __invert__(self):
return QNot(self)
obj = deepcopy(self)
obj.negate()
return obj
class QNot(Q):
"""
Encapsulates the negation of a Q object.
"""
def __init__(self, q):
"""Creates the negation of the Q object passed in."""
super(QNot, self).__init__()
self.add(q, self.AND)
self.negate()
def __invert__(self):
return self.children[0]
def not_q(q):
return ~q

View File

@ -49,10 +49,12 @@ class WhereNode(tree.Node):
format = '(%s)'
elif isinstance(child, tree.Node):
sql, params = self.as_sql(child, qn)
if child.negated:
format = 'NOT (%s)'
if len(child.children) == 1:
format = '%s'
else:
format = '(%s)'
if child.negated:
format = 'NOT %s' % format
else:
sql, params = self.make_atom(child, qn)
format = '%s'

View File

@ -3,7 +3,7 @@ A class for storing a tree graph. Primarily used for filter constructs in the
ORM.
"""
import copy
from copy import deepcopy
class Node(object):
"""
@ -15,24 +15,27 @@ class Node(object):
# subclasses will usually override the value.
default = 'DEFAULT'
def __init__(self, children=None, connector=None):
def __init__(self, children=None, connector=None, negated=False):
self.children = children and children[:] or []
self.connector = connector or self.default
self.subtree_parents = []
self.negated = False
self.negated = negated
def __str__(self):
if self.negated:
return '(NOT (%s: %s))' % (self.connector, ', '.join([str(c) for c
in self.children]))
return '(%s: %s)' % (self.connector, ', '.join([str(c) for c in
self.children]))
self.children]))
def __deepcopy__(self, memodict):
"""
Utility method used by copy.deepcopy().
"""
obj = self.__class__(connector=self.connector)
obj.children = copy.deepcopy(self.children, memodict)
obj.subtree_parents = copy.deepcopy(self.subtree_parents, memodict)
obj.negated = self.negated
obj = Node(connector=self.connector, negated=self.negated)
obj.__class__ = self.__class__
obj.children = deepcopy(self.children, memodict)
obj.subtree_parents = deepcopy(self.subtree_parents, memodict)
return obj
def __len__(self):
@ -63,13 +66,13 @@ class Node(object):
if len(self.children) < 2:
self.connector = conn_type
if self.connector == conn_type:
if isinstance(node, Node) and (node.connector == conn_type
or len(node) == 1):
if isinstance(node, Node) and (node.connector == conn_type or
len(node) == 1):
self.children.extend(node.children)
else:
self.children.append(node)
else:
obj = Node(self.children, self.connector)
obj = Node(self.children, self.connector, self.negated)
self.connector = conn_type
self.children = [obj, node]
@ -80,8 +83,7 @@ class Node(object):
Interpreting the meaning of this negate is up to client code. This
method is useful for implementing "not" arrangements.
"""
self.children = [NegatedNode(self.children, self.connector,
old_state=self.negated)]
self.children = [Node(self.children, self.connector, not self.negated)]
self.connector = self.default
def start_subtree(self, conn_type):
@ -93,11 +95,14 @@ class Node(object):
if len(self.children) == 1:
self.connector = conn_type
elif self.connector != conn_type:
self.children = [Node(self.children, self.connector)]
self.children = [Node(self.children, self.connector, self.negated)]
self.connector = conn_type
self.negated = False
self.subtree_parents.append(Node(self.children, self.connector))
self.subtree_parents.append(Node(self.children, self.connector,
self.negated))
self.connector = self.default
self.negated = False
self.children = []
def end_subtree(self):
@ -110,15 +115,7 @@ class Node(object):
obj = self.subtree_parents.pop()
node = Node(self.children, self.connector)
self.connector = obj.connector
self.negated = obj.negated
self.children = obj.children
self.children.append(node)
class NegatedNode(Node):
"""
A class that indicates the connector type should be negated (whatever that
means -- it's up to the client) when used by the client code.
"""
def __init__(self, children=None, connector=None, old_state=True):
super(NegatedNode, self).__init__(children, connector)
self.negated = not old_state