35
42
storing any reference to field objects). Otherwise, the 'data' is
36
43
stored unchanged and can be anything with an 'as_sql()' method.
38
# Because of circular imports, we need to import this here.
39
from django.db.models.base import ObjectDoesNotExist
41
45
if not isinstance(data, (list, tuple)):
42
46
super(WhereNode, self).add(data, connector)
45
alias, col, field, lookup_type, value = data
48
params = field.get_db_prep_lookup(lookup_type, value)
49
db_type = field.db_type()
51
# This is possible when we add a comparison to NULL sometimes
52
# (we don't really need to waste time looking up the associated
54
params = Field().get_db_prep_lookup(lookup_type, value)
56
except ObjectDoesNotExist:
57
# This can happen when trying to insert a reference to a null pk.
58
# We break out of the normal path and indicate there's nothing to
60
super(WhereNode, self).add(NothingNode(), connector)
49
obj, lookup_type, value = data
50
if hasattr(value, '__iter__') and hasattr(value, 'next'):
51
# Consume any generators immediately, so that we can determine
52
# emptiness and transform any non-empty values correctly.
54
if hasattr(obj, "process"):
56
obj, params = obj.process(lookup_type, value)
57
except (EmptyShortCircuit, EmptyResultSet):
58
# There are situations where we want to short-circuit any
59
# comparisons and make sure that nothing is returned. One
60
# example is when checking for a NULL pk value, or the
62
super(WhereNode, self).add(NothingNode(), connector)
65
params = Field().get_db_prep_lookup(lookup_type, value)
67
# The "annotation" parameter is used to pass auxilliary information
68
# about the value(s) to the query construction. Specifically, datetime
69
# and empty values need special handling. Other types could be used
70
# here in the future (using Python types is suggested for consistency).
62
71
if isinstance(value, datetime.datetime):
63
72
annotation = datetime.datetime
73
elif hasattr(value, 'value_annotation'):
74
annotation = value.value_annotation
65
76
annotation = bool(value)
66
super(WhereNode, self).add((alias, col, db_type, lookup_type,
67
annotation, params), connector)
78
super(WhereNode, self).add((obj, lookup_type, annotation, params),
69
81
def as_sql(self, qn=None):
130
144
Returns the string for the SQL fragment and the parameters to use for
133
table_alias, name, db_type, lookup_type, value_annot, params = child
135
lhs = '%s.%s' % (qn(table_alias), qn(name))
147
lvalue, lookup_type, value_annot, params = child
148
if isinstance(lvalue, tuple):
149
# A direct database column lookup.
150
field_sql = self.sql_for_columns(lvalue, qn)
138
field_sql = connection.ops.field_cast_sql(db_type) % lhs
152
# A smart object with an as_sql() method.
153
field_sql = lvalue.as_sql(quote_func=qn)
140
155
if value_annot is datetime.datetime:
141
156
cast_sql = connection.ops.datetime_cast_sql()
145
if isinstance(params, QueryWrapper):
146
extra, params = params.data
160
if hasattr(params, 'as_sql'):
161
extra, params = params.as_sql(qn)
150
166
if lookup_type in connection.operators:
151
format = "%s %%s %s" % (connection.ops.lookup_cast(lookup_type),
167
format = "%s %%s %%s" % (connection.ops.lookup_cast(lookup_type),)
153
168
return (format % (field_sql,
154
connection.operators[lookup_type] % cast_sql), params)
169
connection.operators[lookup_type] % cast_sql,
156
172
if lookup_type == 'in':
157
173
if not value_annot:
163
179
elif lookup_type in ('range', 'year'):
164
180
return ('%s BETWEEN %%s and %%s' % field_sql, params)
165
elif lookup_type in ('month', 'day'):
166
return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type,
181
elif lookup_type in ('month', 'day', 'week_day'):
182
return ('%s = %%s' % connection.ops.date_extract_sql(lookup_type, field_sql),
168
184
elif lookup_type == 'isnull':
169
185
return ('%s IS %sNULL' % (field_sql,
170
186
(not value_annot and 'NOT ' or '')), ())
176
192
raise TypeError('Invalid lookup_type: %r' % lookup_type)
194
def sql_for_columns(self, data, qn):
196
Returns the SQL fragment used for the left-hand side of a column
197
constraint (for example, the "T1.foo" portion in the clause
198
"WHERE ... T1.foo = 6").
200
table_alias, name, db_type = data
202
lhs = '%s.%s' % (qn(table_alias), qn(name))
205
return connection.ops.field_cast_sql(db_type) % lhs
178
207
def relabel_aliases(self, change_map, node=None):
180
209
Relabels the alias values of any children. 'change_map' is a dictionary
188
217
elif isinstance(child, tree.Node):
189
218
self.relabel_aliases(change_map, child)
191
if child[0] in change_map:
192
node.children[pos] = (change_map[child[0]],) + child[1:]
220
if isinstance(child[0], (list, tuple)):
222
if elt[0] in change_map:
223
elt[0] = change_map[elt[0]]
224
node.children[pos] = (tuple(elt),) + child[1:]
226
child[0].relabel_aliases(change_map)
228
# Check if the query value also requires relabelling
229
if hasattr(child[3], 'relabel_aliases'):
230
child[3].relabel_aliases(change_map)
194
232
class EverythingNode(object):
211
249
def relabel_aliases(self, change_map, node=None):
252
class Constraint(object):
254
An object that can be passed to WhereNode.add() and knows how to
255
pre-process itself prior to including in the WhereNode.
257
def __init__(self, alias, col, field):
258
self.alias, self.col, self.field = alias, col, field
260
def process(self, lookup_type, value):
262
Returns a tuple of data suitable for inclusion in a WhereNode
265
# Because of circular imports, we need to import this here.
266
from django.db.models.base import ObjectDoesNotExist
269
params = self.field.get_db_prep_lookup(lookup_type, value)
270
db_type = self.field.db_type()
272
# This branch is used at times when we add a comparison to NULL
273
# (we don't really want to waste time looking up the associated
274
# field object at the calling location).
275
params = Field().get_db_prep_lookup(lookup_type, value)
277
except ObjectDoesNotExist:
278
raise EmptyShortCircuit
280
return (self.alias, self.col, db_type), params