From aca951da3954563ec8d43aa1bc3eae907ff67a91 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 17 Jun 2011 11:31:26 +0200 Subject: [PATCH 1/9] [REF] orm: simpler `_find` function, renamed `locate`. bzr revid: vmt@openerp.com-20110617093126-v0951wvy48r1db4h --- openerp/osv/orm.py | 63 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 4a86d6a4fea..a186b0cb0c4 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1615,38 +1615,39 @@ class orm_template(object): raise AttributeError("View definition error for inherited view '%s' on model '%s': %s" % (child_view.xml_id, self._name, error_msg)) - def _inherit_apply(src, inherit, inherit_id=None): - def _find(node, node2): - if node2.tag == 'xpath': - res = node.xpath(node2.get('expr')) - if res: - return res[0] - else: - return None - else: - for n in node.getiterator(node2.tag): - res = True - if node2.tag == 'field': - # only compare field names, a field can be only once in a given view - # at a given level (and for multilevel expressions, we should use xpath - # inheritance spec anyway) - if node2.get('name') == n.get('name'): - return n - else: - continue - for attr in node2.attrib: - if attr == 'position': - continue - if n.get(attr): - if n.get(attr) == node2.get(attr): - continue - res = False - if res: - return n + def locate(source, spec): + """ Locate a node in a source (parent) view. + + Given a complete source (parent) view, and a 'spec' + node (a node in a inheriting view that specifies the + location in the source view of what should be changed), + return (if it exists) the node in the source view matching + the specification. + + """ + if spec.tag == 'xpath': + nodes = source.xpath(spec.get('expr')) + return nodes[0] if nodes else None + elif spec.tag == 'field': + # Only compare the field name: a field can be only once in a given view + # at a given level (and for multilevel expressions, we should use xpath + # inheritance spec anyway). + for node in source.getiterator('field'): + if node.get('name') == spec.get('name'): + return node + return None + else: + for node in source.getiterator(spec.tag): + good = True + for attr in spec.attrib: + if attr != 'position' and node.get(attr) and node.get(attr) != spec.get(attr): + good = False + break + if good: + return node return None - # End: _find(node, node2) - + def _inherit_apply(src, inherit, inherit_id=None): doc_dest = etree.fromstring(encode(inherit)) toparse = [doc_dest] @@ -1657,7 +1658,7 @@ class orm_template(object): if node2.tag == 'data': toparse += [ c for c in doc_dest ] continue - node = _find(src, node2) + node = locate(src, node2) if node is not None: pos = 'inside' if node2.get('position'): From f46cfc589de19910ee83f3192952794435a1dffb Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 17 Jun 2011 17:44:40 +0200 Subject: [PATCH 2/9] [REF] fields_viw_get: trying to get something clearer... bzr revid: vmt@openerp.com-20110617154440-i013qj8qukxhqhnl --- openerp/osv/orm.py | 136 ++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index a186b0cb0c4..54e8a041d4f 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1318,7 +1318,7 @@ class orm_template(object): return False def __view_look_dom(self, cr, user, node, view_id, context=None): - if not context: + if context is None: context = {} result = False fields = {} @@ -1329,8 +1329,8 @@ class orm_template(object): return s.encode('utf8') return s - # return True if node can be displayed to current user def check_group(node): + """ Set invisible to true if the user is not in the specified groups. """ if node.get('groups'): groups = node.get('groups').split(',') access_pool = self.pool.get('ir.model.access') @@ -1340,9 +1340,6 @@ class orm_template(object): if 'attrs' in node.attrib: del(node.attrib['attrs']) #avoid making field visible later del(node.attrib['groups']) - return can_see - else: - return True if node.tag in ('field', 'node', 'arrow'): if node.get('object'): @@ -1421,8 +1418,7 @@ class orm_template(object): if node.get(additional_field): fields[node.get(additional_field)] = {} - if 'groups' in node.attrib: - check_group(node) + check_group(node) # translate view if ('lang' in context) and not result: @@ -1454,6 +1450,7 @@ class orm_template(object): return fields def _disable_workflow_buttons(self, cr, user, node): + """ Set the buttons in node to readonly if the user can't activate them. """ if user == 1: # admin user can always activate workflow buttons return node @@ -1616,13 +1613,13 @@ class orm_template(object): % (child_view.xml_id, self._name, error_msg)) def locate(source, spec): - """ Locate a node in a source (parent) view. + """ Locate a node in a source (parent) architecture. - Given a complete source (parent) view, and a 'spec' - node (a node in a inheriting view that specifies the - location in the source view of what should be changed), - return (if it exists) the node in the source view matching - the specification. + Given a complete source (parent) architecture (i.e. the field + `arch` in a view), and a 'spec' node (a node in a inheriting + view that specifies the location in the source view of what + should be changed), return (if it exists) the node in the + source view matching the specification. """ if spec.tag == 'xpath': @@ -1647,32 +1644,38 @@ class orm_template(object): return node return None - def _inherit_apply(src, inherit, inherit_id=None): - doc_dest = etree.fromstring(encode(inherit)) - toparse = [doc_dest] + def apply_specs(source, inherit, inherit_id=None): + """ Apply an inheriting view. - while len(toparse): - node2 = toparse.pop(0) - if isinstance(node2, SKIPPED_ELEMENT_TYPES): + Apply to a source architecture all the spec nodes (i.e. nodes + describing where and what changes to apply to some parent + architecture) given by an inheriting view. + + """ + specs_tree = etree.fromstring(encode(inherit)) + # Queue of specification nodes (i.e. nodes describing where and + # changes to apply to some parent architecture). + specs = [specs_tree] + + while len(specs): + spec = specs.pop(0) + if isinstance(spec, SKIPPED_ELEMENT_TYPES): continue - if node2.tag == 'data': - toparse += [ c for c in doc_dest ] + if spec.tag == 'data': + specs += [ c for c in specs_tree ] continue - node = locate(src, node2) + node = locate(source, spec) if node is not None: - pos = 'inside' - if node2.get('position'): - pos = node2.get('position') + pos = spec.get('position', 'inside') if pos == 'replace': - parent = node.getparent() - if parent is None: - src = copy.deepcopy(node2[0]) + if node.getparent() is None: + source = copy.deepcopy(spec[0]) else: - for child in node2: + for child in spec: node.addprevious(child) node.getparent().remove(node) elif pos == 'attributes': - for child in node2.getiterator('attribute'): + for child in spec.getiterator('attribute'): attribute = (child.get('name'), child.text and child.text.encode('utf8') or None) if attribute[1]: node.set(attribute[0], attribute[1]) @@ -1680,7 +1683,7 @@ class orm_template(object): del(node.attrib[attribute[0]]) else: sib = node.getnext() - for child in node2: + for child in spec: if pos == 'inside': node.append(child) elif pos == 'after': @@ -1695,22 +1698,31 @@ class orm_template(object): raise_view_error("Invalid position value: '%s'" % pos, inherit_id) else: attrs = ''.join([ - ' %s="%s"' % (attr, node2.get(attr)) - for attr in node2.attrib + ' %s="%s"' % (attr, spec.get(attr)) + for attr in spec.attrib if attr != 'position' ]) - tag = "<%s%s>" % (node2.tag, attrs) + tag = "<%s%s>" % (spec.tag, attrs) raise_view_error("Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, inherit_id) - return src - # End: _inherit_apply(src, inherit) + return source + + def apply_chained_specs(source, inherit_id): + """ Apply all the (directly and indirectly) inheriting views. """ + # get all views which inherit from (ie modify) this view + cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name)) + sql_inherit = cr.fetchall() + for (inherit, id) in sql_inherit: + source = apply_specs(source, inherit, id) + source = apply_chained_specs(source, id) + return source result = {'type': view_type, 'model': self._name} - ok = True sql_res = False parent_view_model = None - while ok: - view_ref = context.get(view_type + '_view_ref', False) + view_ref = context.get(view_type + '_view_ref') + # Search for a root (i.e. without any parent) view. + while True: if view_ref and not view_id: if '.' in view_ref: module, view_ref = view_ref.split('.', 1) @@ -1724,44 +1736,30 @@ class orm_template(object): FROM ir_ui_view WHERE id=%s""", (view_id,)) else: - cr.execute('''SELECT - arch,name,field_parent,id,type,inherit_id,model - FROM - ir_ui_view - WHERE - model=%s AND - type=%s AND - inherit_id IS NULL - ORDER BY priority''', (self._name, view_type)) - sql_res = cr.fetchone() + cr.execute("""SELECT arch,name,field_parent,id,type,inherit_id,model + FROM ir_ui_view + WHERE model=%s AND type=%s AND inherit_id IS NULL + ORDER BY priority""", (self._name, view_type)) + sql_res = cr.dictfetchone() if not sql_res: break - ok = sql_res[5] - view_id = ok or sql_res[3] - parent_view_model = sql_res[6] + view_id = sql_res['inherit_id'] or sql_res['id'] + parent_view_model = sql_res['model'] + if not sql_res['inherit_id']: + break # if a view was found if sql_res: - result['type'] = sql_res[4] - result['view_id'] = sql_res[3] - result['arch'] = sql_res[0] + result['type'] = sql_res['type'] + result['view_id'] = sql_res['id'] - def _inherit_apply_rec(result, inherit_id): - # get all views which inherit from (ie modify) this view - cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name)) - sql_inherit = cr.fetchall() - for (inherit, id) in sql_inherit: - result = _inherit_apply(result, inherit, id) - result = _inherit_apply_rec(result, id) - return result + source = etree.fromstring(encode(sql_res['arch'])) + result['arch'] = apply_chained_specs(source, result['view_id']) - inherit_result = etree.fromstring(encode(result['arch'])) - result['arch'] = _inherit_apply_rec(inherit_result, sql_res[3]) - - result['name'] = sql_res[1] - result['field_parent'] = sql_res[2] or False + result['name'] = sql_res['nam'] + result['field_parent'] = sql_res['field_parent'] or False else: # otherwise, build some kind of default view @@ -1791,7 +1789,7 @@ class orm_template(object): xml = self.__get_default_search_view(cr, user, context) else: - xml = '' # what happens here, graph case? + # what happens here, graph case? raise except_orm(_('Invalid Architecture!'), _("There is no view of type '%s' defined for the structure!") % view_type) result['arch'] = etree.fromstring(encode(xml)) result['name'] = 'default' From 8645487d610560dc19dc15845742bc05fce9a7aa Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 20 Jun 2011 11:56:42 +0200 Subject: [PATCH 3/9] [FIX] orm: typo in fields_view_get. bzr revid: vmt@openerp.com-20110620095642-3vx11f7cqad2e71k --- openerp/osv/orm.py | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 54e8a041d4f..b79ab569bdd 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1616,11 +1616,15 @@ class orm_template(object): """ Locate a node in a source (parent) architecture. Given a complete source (parent) architecture (i.e. the field - `arch` in a view), and a 'spec' node (a node in a inheriting + `arch` in a view), and a 'spec' node (a node in an inheriting view that specifies the location in the source view of what should be changed), return (if it exists) the node in the source view matching the specification. + :param source: a parent architecture to modify + :param spec: a modifying node in an inheriting view + :return: a node in the source matching the spec + """ if spec.tag == 'xpath': nodes = source.xpath(spec.get('expr')) @@ -1644,15 +1648,20 @@ class orm_template(object): return node return None - def apply_specs(source, inherit, inherit_id=None): + def apply_inheritance_specs(source, specs_arch, inherit_id=None): """ Apply an inheriting view. Apply to a source architecture all the spec nodes (i.e. nodes describing where and what changes to apply to some parent architecture) given by an inheriting view. + :param source: a parent architecture to modify + :param specs_arch: a modifying architecture in an inheriting view + :param inherit_id: the database id of the inheriting view + :return: a modified source where the specs are applied + """ - specs_tree = etree.fromstring(encode(inherit)) + specs_tree = etree.fromstring(encode(specs_arch)) # Queue of specification nodes (i.e. nodes describing where and # changes to apply to some parent architecture). specs = [specs_tree] @@ -1706,14 +1715,22 @@ class orm_template(object): raise_view_error("Element '%s' not found in parent view '%%(parent_xml_id)s'" % tag, inherit_id) return source - def apply_chained_specs(source, inherit_id): - """ Apply all the (directly and indirectly) inheriting views. """ + def apply_view_inheritance(source, inherit_id): + """ Apply all the (directly and indirectly) inheriting views. + + :param source: a parent architecture to modify (with parent + modifications already applied) + :param inherit_id: the database id of the parent view + :return: a modified source where all the modifying architecture + are applied + + """ # get all views which inherit from (ie modify) this view cr.execute('select arch,id from ir_ui_view where inherit_id=%s and model=%s order by priority', (inherit_id, self._name)) sql_inherit = cr.fetchall() for (inherit, id) in sql_inherit: - source = apply_specs(source, inherit, id) - source = apply_chained_specs(source, id) + source = apply_inheritance_specs(source, inherit, id) + source = apply_view_inheritance(source, id) return source result = {'type': view_type, 'model': self._name} @@ -1756,9 +1773,9 @@ class orm_template(object): result['view_id'] = sql_res['id'] source = etree.fromstring(encode(sql_res['arch'])) - result['arch'] = apply_chained_specs(source, result['view_id']) + result['arch'] = apply_view_inheritance(source, result['view_id']) - result['name'] = sql_res['nam'] + result['name'] = sql_res['name'] result['field_parent'] = sql_res['field_parent'] or False else: From 53f594eb67fa88e8063dfafd56d4d9369be1718e Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 20 Jun 2011 14:01:57 +0200 Subject: [PATCH 4/9] [REF] orm/fields_view_get: replaced simple loop by dict.update(). bzr revid: vmt@openerp.com-20110620120157-xwf09egoyq3xc5qo --- openerp/osv/orm.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index b79ab569bdd..55236b7fb90 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1482,12 +1482,10 @@ class orm_template(object): if node.tag == 'diagram': if node.getchildren()[0].tag == 'node': node_fields = self.pool.get(node.getchildren()[0].get('object')).fields_get(cr, user, fields_def.keys(), context) + fields.update(node_fields) if node.getchildren()[1].tag == 'arrow': arrow_fields = self.pool.get(node.getchildren()[1].get('object')).fields_get(cr, user, fields_def.keys(), context) - for key, value in node_fields.items(): - fields[key] = value - for key, value in arrow_fields.items(): - fields[key] = value + fields.update(arrow_fields) else: fields = self.fields_get(cr, user, fields_def.keys(), context) for field in fields_def: From ee5eb8095165df7a0d8ef66862eb523f6a022f20 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 20 Jun 2011 14:06:00 +0200 Subject: [PATCH 5/9] [FIX] orm/fields_view_get: translate correctly confirm/sum/help: - view_header_get can override the string attribute but should not prevent the translation of the other attributes. - the problem goes back to revno 319 when there was only a string and sum was added. bzr revid: vmt@openerp.com-20110620120600-lu9csho8ws2habfp --- openerp/osv/orm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 55236b7fb90..7c97554738c 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1421,8 +1421,8 @@ class orm_template(object): check_group(node) # translate view - if ('lang' in context) and not result: - if node.get('string'): + if 'lang' in context: + if node.get('string') and not result: trans = self.pool.get('ir.translation')._get_source(cr, user, self._name, 'view', context['lang'], node.get('string')) if trans == node.get('string') and ('base_model_name' in context): # If translation is same as source, perhaps we'd have more luck with the alternative model name From 41b066a085d1ab832cf6c9230a8fc26515485119 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 20 Jun 2011 16:10:05 +0200 Subject: [PATCH 6/9] [FIX] fields_view_get: corrected an error introduced at rev 3467. bzr revid: vmt@openerp.com-20110620141005-togs3phmto931wle --- openerp/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 7c97554738c..5067e00e370 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1639,7 +1639,7 @@ class orm_template(object): for node in source.getiterator(spec.tag): good = True for attr in spec.attrib: - if attr != 'position' and node.get(attr) and node.get(attr) != spec.get(attr): + if attr != 'position' and (not node.get(attr) or node.get(attr) != spec.get(attr)): good = False break if good: From 802ecdd6cf0063017a625cc70410062df83e5a1a Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 21 Jun 2011 16:45:43 +0200 Subject: [PATCH 7/9] [REF] orm/_inherits_reload: unnecessary dict.update() (the entries are manually updated afterwards). bzr revid: vmt@openerp.com-20110621144543-z03m9rceohmayjxu --- openerp/osv/orm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 5067e00e370..3212c09410e 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3150,7 +3150,6 @@ class orm(orm_template): res = {} for table in self._inherits: other = self.pool.get(table) - res.update(other._inherit_fields) for col in other._columns.keys(): res[col] = (table, self._inherits[table], other._columns[col]) for col in other._inherit_fields.keys(): From f3b7293c2e7adc972b4f8f620f15f0905fb64322 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 21 Jun 2011 17:53:42 +0200 Subject: [PATCH 8/9] [REF] orm: add a column_info class to represent entries in _inherit_fields, code comes from the trunk-sharing-features branch (by odo). bzr revid: vmt@openerp.com-20110621155342-8a3o153rkpsd5s12 --- openerp/osv/fields.py | 19 +++++++++++++++++++ openerp/osv/orm.py | 22 +++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index f55e4b9c027..eb4a073e3b2 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1169,5 +1169,24 @@ def field_to_dict(self, cr, user, context, field): return res + +class column_info(object): + """Struct containing details about an osv column, either one local to + its model, or one inherited via _inherits. + + :attr name: name of the column + :attr column: column instance, subclass of osv.fields._column + :attr parent_model: if the column is inherited, name of the model + that contains it, None for local columns. + :attr parent_column: the name of the column containing the m2o + relationship to the parent model that contains + this column, None for local columns. + """ + def __init__(self, name, column, parent_model=None, parent_column=None): + self.name = name + self.column = column + self.parent_model = parent_model + self.parent_column = parent_column + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 3212c09410e..9a1fc307b12 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -477,6 +477,11 @@ class orm_template(object): # r is the (local) field towards m, # and f is the _column object itself. _inherit_fields = {} + # Mapping field name/column_info object + # This is similar to _inherit_fields but: + # 1. includes self fields, + # 2. uses column_info instead of a triple. + _all_columns = {} _table = None _invalids = set() _log_create = False @@ -1263,7 +1268,7 @@ class orm_template(object): def fields_get(self, cr, user, allfields=None, context=None, write_access=True): - """ Returns the definition of each field. + """ Return the definition of each field. The returned value is a dictionary (indiced by field name) of dictionaries. The _inherits'd fields are included. The string, @@ -3141,6 +3146,7 @@ class orm(orm_template): if self._name in obj._inherits: obj._inherits_reload() + def _inherits_reload(self): """ Recompute the _inherit_fields mapping. @@ -3155,8 +3161,22 @@ class orm(orm_template): for col in other._inherit_fields.keys(): res[col] = (table, self._inherits[table], other._inherit_fields[col][2]) self._inherit_fields = res + self._all_columns = self._get_column_infos() self._inherits_reload_src() + + def _get_column_infos(self): + """Returns a dict mapping all fields names (direct fields and + inherited field via _inherits) to a ``column_info`` struct + giving detailed columns """ + result = {} + for k, (parent, m2o, col) in self._inherit_fields.iteritems(): + result[k] = fields.column_info(k, col, parent, m2o) + for k, col in self._columns.iteritems(): + result[k] = fields.column_info(k, col) + return result + + def _inherits_check(self): for table, field_name in self._inherits.items(): if field_name not in self._columns: From ab0d7214165753ebf1558c9547de77193573b441 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Mon, 27 Jun 2011 11:50:59 +0200 Subject: [PATCH 9/9] [REF] orm: added TODOs. bzr revid: vmt@openerp.com-20110627095059-lf8lctk1z0yawgrk --- openerp/osv/orm.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 9a1fc307b12..757e33ddf9c 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1561,6 +1561,7 @@ class orm_template(object): tree_view = self.fields_view_get(cr, uid, False, 'tree', context=context) fields_to_search = set() + # TODO it seems _all_columns could be used instead of fields_get (no need for translated fields info) fields = self.fields_get(cr, uid, context=context) for field in fields: if fields[field].get('select'): @@ -1784,6 +1785,7 @@ class orm_template(object): # otherwise, build some kind of default view if view_type == 'form': + # TODO it seems fields_get can be replaced by _all_columns (no need for translation) res = self.fields_get(cr, user, context=context) xml = ' ' \ '
' % (self._description,) @@ -2366,6 +2368,7 @@ class orm(orm_template): groupby_def = self._columns.get(groupby) or (self._inherit_fields.get(groupby) and self._inherit_fields.get(groupby)[2]) assert groupby_def and groupby_def._classic_write, "Fields in 'groupby' must be regular database-persisted fields (no function or related fields), or function fields with store=True" + # TODO it seems fields_get can be replaced by _all_columns (no need for translation) fget = self.fields_get(cr, uid, fields) float_int_fields = filter(lambda x: fget[x]['type'] in ('float', 'integer'), fields) flist = '' @@ -4390,6 +4393,7 @@ class orm(orm_template): else: raise IndexError( _("Record #%d of %s not found, cannot copy!") %( id, self._name)) + # TODO it seems fields_get can be replaced by _all_columns (no need for translation) fields = self.fields_get(cr, uid, context=context) for f in fields: ftype = fields[f]['type'] @@ -4447,6 +4451,7 @@ class orm(orm_template): seen_map[self._name].append(old_id) trans_obj = self.pool.get('ir.translation') + # TODO it seems fields_get can be replaced by _all_columns (no need for translation) fields = self.fields_get(cr, uid, context=context) translation_records = []