summaryrefslogtreecommitdiff
path: root/django/db/models/sql/where.py
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-07-04 06:42:58 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2008-07-04 06:42:58 +0000
commit6dd2b5468fa275d53aa60fdcaff8c28bdc5e9c25 (patch)
treea1d2f8cf21e1e9fb7a5ed788bea45511c73cc4aa /django/db/models/sql/where.py
parent3b6487130ae2b8f3bbd4c18a44403ccdedd24f05 (diff)
Redo the changes in [7773] in a better way.
This removes some of the leaky abstraction problems (lifting WhereNode internals into the Query class) from that commit and makes it possible for extensions to WhereNode to have access to the field instances. It's also backwards-compatible with pre-[7773] code, which is also better. git-svn-id: http://code.djangoproject.com/svn/django/trunk@7835 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/models/sql/where.py')
-rw-r--r--django/db/models/sql/where.py71
1 files changed, 48 insertions, 23 deletions
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index bf45bceb4b..18e4bf2f7e 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -27,7 +27,36 @@ class WhereNode(tree.Node):
"""
default = AND
- def as_sql(self, node=None, qn=None):
+ def add(self, data, connector):
+ """
+ Add a node to the where-tree. If the data is a list or tuple, it is
+ expected to be of the form (alias, col_name, field_obj, lookup_type,
+ value), which is then slightly munged before being stored (to avoid
+ storing any reference to field objects). Otherwise, the 'data' is
+ stored unchanged and can be anything with an 'as_sql()' method.
+ """
+ if not isinstance(data, (list, tuple)):
+ super(WhereNode, self).add(data, connector)
+ return
+
+ alias, col, field, lookup_type, value = data
+ if field:
+ params = field.get_db_prep_lookup(lookup_type, value)
+ db_type = field.db_type()
+ else:
+ # This is possible when we add a comparison to NULL sometimes (we
+ # don't really need to waste time looking up the associated field
+ # object).
+ params = Field().get_db_prep_lookup(lookup_type, value)
+ db_type = None
+ if isinstance(value, datetime.datetime):
+ annotation = datetime.datetime
+ else:
+ annotation = bool(value)
+ super(WhereNode, self).add((alias, col, db_type, lookup_type,
+ annotation, params), connector)
+
+ def as_sql(self, qn=None):
"""
Returns the SQL version of the where clause and the value to be
substituted in. Returns None, None if this node is empty.
@@ -36,60 +65,56 @@ class WhereNode(tree.Node):
(generally not needed except by the internal implementation for
recursion).
"""
- if node is None:
- node = self
if not qn:
qn = connection.ops.quote_name
- if not node.children:
+ if not self.children:
return None, []
result = []
result_params = []
empty = True
- for child in node.children:
+ for child in self.children:
try:
if hasattr(child, 'as_sql'):
sql, params = child.as_sql(qn=qn)
- format = '(%s)'
- elif isinstance(child, tree.Node):
- sql, params = self.as_sql(child, qn)
- if child.negated:
- format = 'NOT (%s)'
- elif len(child.children) == 1:
- format = '%s'
- else:
- format = '(%s)'
else:
+ # A leaf node in the tree.
sql, params = self.make_atom(child, qn)
- format = '%s'
except EmptyResultSet:
- if node.connector == AND and not node.negated:
+ if self.connector == AND and not self.negated:
# We can bail out early in this particular case (only).
raise
- elif node.negated:
+ elif self.negated:
empty = False
continue
except FullResultSet:
if self.connector == OR:
- if node.negated:
+ if self.negated:
empty = True
break
# We match everything. No need for any constraints.
return '', []
- if node.negated:
+ if self.negated:
empty = True
continue
empty = False
if sql:
- result.append(format % sql)
+ result.append(sql)
result_params.extend(params)
if empty:
raise EmptyResultSet
- conn = ' %s ' % node.connector
- return conn.join(result), result_params
+
+ conn = ' %s ' % self.connector
+ sql_string = conn.join(result)
+ if sql_string:
+ if self.negated:
+ sql_string = 'NOT (%s)' % sql_string
+ elif len(self.children) != 1:
+ sql_string = '(%s)' % sql_string
+ return sql_string, result_params
def make_atom(self, child, qn):
"""
- Turn a tuple (table_alias, field_name, db_type, lookup_type,
+ Turn a tuple (table_alias, column_name, db_type, lookup_type,
value_annot, params) into valid SQL.
Returns the string for the SQL fragment and the parameters to use for