|
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 |
|
14 def prepare(self): |
|
15 return self |
|
16 |
|
17 def as_sql(self, qn, connection): |
|
18 return self.expression.evaluate(self, qn, connection) |
|
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 |
|
59 def evaluate_node(self, node, qn, connection): |
|
60 expressions = [] |
|
61 expression_params = [] |
|
62 for child in node.children: |
|
63 if hasattr(child, 'evaluate'): |
|
64 sql, params = child.evaluate(self, qn, connection) |
|
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 |
|
79 def evaluate_leaf(self, node, qn, connection): |
|
80 col = self.cols[node] |
|
81 if hasattr(col, 'as_sql'): |
|
82 return col.as_sql(qn, connection), () |
|
83 else: |
|
84 return '%s.%s' % (qn(col[0]), qn(col[1])), () |