[IMP] models: in _read_from_database(), use the Query object to build the query

This makes the query construction more robust, as it handles joins for
conditions and ORDER BY clauses.  It also makes it easier to read() from
several tables (like inherited fields).
This commit is contained in:
Raphael Collet 2015-02-12 12:10:15 +01:00
parent 3e18166ea4
commit 2c261a2987
1 changed files with 16 additions and 21 deletions

View File

@ -3232,20 +3232,15 @@ class BaseModel(object):
env = self.env env = self.env
cr, user, context = env.args cr, user, context = env.args
# FIXME: The query construction needs to be rewritten using the internal Query # make a query object for selecting ids, and apply security rules to it
# object, as in search(), to avoid ambiguous column references when query = Query(['"%s"' % self._table], ['"%s".id IN %%s' % self._table], [])
# reading/sorting on a table that is auto_joined to another table with self._apply_ir_rules(query, 'read')
# common columns (e.g. the magical columns) order_str = self._generate_order_by(None, query)
# Construct a clause for the security rules.
# 'tables' holds the list of tables necessary for the SELECT, including
# the ir.rule clauses, and contains at least self._table.
rule_clause, rule_params, tables = env['ir.rule'].domain_get(self._name, 'read')
# determine the fields that are stored as columns in self._table # determine the fields that are stored as columns in self._table
fields_pre = [f for f in field_names if self._columns[f]._classic_write] fields_pre = [f for f in field_names if self._columns[f]._classic_write]
# we need fully-qualified column names in case len(tables) > 1 # the query may involve several tables: we need fully-qualified names
def qualify(f): def qualify(f):
if isinstance(self._columns.get(f), fields.binary) and \ if isinstance(self._columns.get(f), fields.binary) and \
context.get('bin_size_%s' % f, context.get('bin_size')): context.get('bin_size_%s' % f, context.get('bin_size')):
@ -3255,20 +3250,20 @@ class BaseModel(object):
return '%s."%s"' % (self._table, f) return '%s."%s"' % (self._table, f)
qual_names = map(qualify, set(fields_pre + ['id'])) qual_names = map(qualify, set(fields_pre + ['id']))
query = """ SELECT %(qual_names)s FROM %(tables)s # determine the actual query to execute
WHERE %(table)s.id IN %%s AND (%(extra)s) from_clause, where_clause, where_params = query.get_sql()
ORDER BY %(order)s query_str = """ SELECT %(qual_names)s FROM %(from_clause)s
""" % { WHERE %(where_clause)s %(order_str)s
'qual_names': ",".join(qual_names), """ % {
'tables': ",".join(tables), 'qual_names': ",".join(qual_names),
'table': self._table, 'from_clause': from_clause,
'extra': " OR ".join(rule_clause) if rule_clause else "TRUE", 'where_clause': where_clause,
'order': self._parent_order or self._order, 'order_str': order_str,
} }
result = [] result = []
for sub_ids in cr.split_for_in_conditions(self.ids): for sub_ids in cr.split_for_in_conditions(self.ids):
cr.execute(query, [tuple(sub_ids)] + rule_params) cr.execute(query_str, [tuple(sub_ids)] + where_params)
result.extend(cr.dictfetchall()) result.extend(cr.dictfetchall())
ids = [vals['id'] for vals in result] ids = [vals['id'] for vals in result]