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