|
0
|
1 |
from django.core.exceptions import FieldError |
|
|
2 |
from django.db.models.fields import FieldDoesNotExist |
|
|
3 |
from django.db.models.sql.constants import LOOKUP_SEP |
|
|
4 |
|
|
|
5 |
class SQLEvaluator(object): |
|
|
6 |
def __init__(self, expression, query, allow_joins=True): |
|
|
7 |
self.expression = expression |
|
|
8 |
self.opts = query.get_meta() |
|
|
9 |
self.cols = {} |
|
|
10 |
|
|
|
11 |
self.contains_aggregate = False |
|
|
12 |
self.expression.prepare(self, query, allow_joins) |
|
|
13 |
|
|
29
|
14 |
def prepare(self): |
|
|
15 |
return self |
|
|
16 |
|
|
|
17 |
def as_sql(self, qn, connection): |
|
|
18 |
return self.expression.evaluate(self, qn, connection) |
|
0
|
19 |
|
|
|
20 |
def relabel_aliases(self, change_map): |
|
|
21 |
for node, col in self.cols.items(): |
|
|
22 |
self.cols[node] = (change_map.get(col[0], col[0]), col[1]) |
|
|
23 |
|
|
|
24 |
##################################################### |
|
|
25 |
# Vistor methods for initial expression preparation # |
|
|
26 |
##################################################### |
|
|
27 |
|
|
|
28 |
def prepare_node(self, node, query, allow_joins): |
|
|
29 |
for child in node.children: |
|
|
30 |
if hasattr(child, 'prepare'): |
|
|
31 |
child.prepare(self, query, allow_joins) |
|
|
32 |
|
|
|
33 |
def prepare_leaf(self, node, query, allow_joins): |
|
|
34 |
if not allow_joins and LOOKUP_SEP in node.name: |
|
|
35 |
raise FieldError("Joined field references are not permitted in this query") |
|
|
36 |
|
|
|
37 |
field_list = node.name.split(LOOKUP_SEP) |
|
|
38 |
if (len(field_list) == 1 and |
|
|
39 |
node.name in query.aggregate_select.keys()): |
|
|
40 |
self.contains_aggregate = True |
|
|
41 |
self.cols[node] = query.aggregate_select[node.name] |
|
|
42 |
else: |
|
|
43 |
try: |
|
|
44 |
field, source, opts, join_list, last, _ = query.setup_joins( |
|
|
45 |
field_list, query.get_meta(), |
|
|
46 |
query.get_initial_alias(), False) |
|
|
47 |
col, _, join_list = query.trim_joins(source, join_list, last, False) |
|
|
48 |
|
|
|
49 |
self.cols[node] = (join_list[-1], col) |
|
|
50 |
except FieldDoesNotExist: |
|
|
51 |
raise FieldError("Cannot resolve keyword %r into field. " |
|
|
52 |
"Choices are: %s" % (self.name, |
|
|
53 |
[f.name for f in self.opts.fields])) |
|
|
54 |
|
|
|
55 |
################################################## |
|
|
56 |
# Vistor methods for final expression evaluation # |
|
|
57 |
################################################## |
|
|
58 |
|
|
29
|
59 |
def evaluate_node(self, node, qn, connection): |
|
0
|
60 |
expressions = [] |
|
|
61 |
expression_params = [] |
|
|
62 |
for child in node.children: |
|
|
63 |
if hasattr(child, 'evaluate'): |
|
29
|
64 |
sql, params = child.evaluate(self, qn, connection) |
|
0
|
65 |
else: |
|
|
66 |
sql, params = '%s', (child,) |
|
|
67 |
|
|
|
68 |
if len(getattr(child, 'children', [])) > 1: |
|
|
69 |
format = '(%s)' |
|
|
70 |
else: |
|
|
71 |
format = '%s' |
|
|
72 |
|
|
|
73 |
if sql: |
|
|
74 |
expressions.append(format % sql) |
|
|
75 |
expression_params.extend(params) |
|
|
76 |
|
|
|
77 |
return connection.ops.combine_expression(node.connector, expressions), expression_params |
|
|
78 |
|
|
29
|
79 |
def evaluate_leaf(self, node, qn, connection): |
|
0
|
80 |
col = self.cols[node] |
|
|
81 |
if hasattr(col, 'as_sql'): |
|
29
|
82 |
return col.as_sql(qn, connection), () |
|
0
|
83 |
else: |
|
|
84 |
return '%s.%s' % (qn(col[0]), qn(col[1])), () |