Odoo 15转16模块迁移:operating_unit_id字段权限报错求助
Odoo 15→16迁移:上下文引用权限组字段报错解决
问题场景
将模块从Odoo 15.0迁移至16.0版本后,在XML视图中为operating_unit_id字段添加权限组operating_unit.group_multi_operating_unit,出现上下文验证报错。该字段已在purchase.order.line和purchase.order模型中创建,删除权限组可正常运行但业务不允许删除。
原视图代码
<record id="purchase_order_form" model="ir.ui.view"> <field name="purchase_order_form">purchase_order_form</field> <field name="model">purchase.order</field> <field name="inherit_id" ref="purchase.purchase_order_form" /> <field name="arch" type="xml"> <field name="partner_ref" position="after"> <field name="requesting_operating_unit_id" groups="operating_unit.group_multi_operating_unit" /> <field name="operating_unit_id" groups="operating_unit.group_multi_operating_unit" /> </field> <field name="order_line" position="attributes"> <attribute name="context">{"default_state": "draft", "default_operating_unit_id": operating_unit_id}</attribute> </field> </field> </record>
报错信息
Traceback (most recent call last): File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1583, in _serve_db return service_model.retrying(self._serve_ir_http, self.env) File "/opt/odoo/custom/src/odoo/odoo/service/model.py", line 134, in retrying result = func() File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1610, in _serve_ir_http response = self.dispatcher.dispatch(rule.endpoint, args) File "/opt/odoo/custom/src/odoo/odoo/http.py", line 1807, in dispatch result = self.request.registry['ir.http']._dispatch(endpoint) File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_http.py", line 154, in _dispatch result = endpoint(**request.params) File "/opt/odoo/custom/src/odoo/odoo/http.py", line 696, in route_wrapper result = endpoint(self, *args, **params_ok) File "/opt/odoo/auto/addons/web/controllers/dataset.py", line 46, in call_button action = self._call_kw(model, method, args, kwargs) File "/opt/odoo/auto/addons/web/controllers/dataset.py", line 33, in _call_kw return call_kw(request.env[model], method, args, kwargs) File "/opt/odoo/custom/src/odoo/odoo/api.py", line 461, in call_kw result = _call_kw_multi(method, model, args, kwargs) File "/opt/odoo/custom/src/odoo/odoo/api.py", line 448, in _call_kw_multi result = method(recs, *args, **kwargs) File "<decorator-gen-75>", line 2, in button_immediate_upgrade File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 76, in check_and_log return method(self, *args, **kwargs) File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 678, in button_immediate_upgrade return self._button_immediate_function(type(self).button_upgrade) File "/opt/odoo/custom/src/odoo/odoo/addons/base/models/ir_module.py", line 615, in _button_immediate_function registry = modules.registry.Registry.new(self._cr.dbname, update_module=True) File "<decorator-gen-14>", line 2, in new File "/opt/odoo/custom/src/odoo/odoo/tools/func.py", line 87, in locked return func(inst, *args, **kwargs) File "/opt/odoo/custom/src/odoo/odoo/modules/registry.py", line 90, in new odoo.modules.load_modules(registry, force_demo, status, update_module) File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 483, in load_modules processed_modules += load_marked_modules(cr, graph, File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 371, in load_marked_modules loaded, processed = load_module_graph( File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 230, in load_module_graph load_data(cr, idref, mode, kind='data', package=package) File "/opt/odoo/custom/src/odoo/odoo/modules/loading.py", line 71, in load_data tools.convert_file(cr, package.name, filename, idref, mode, noupdate, kind) File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 763, in convert_file convert_xml_import(cr, module, fp, idref, mode, noupdate) File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 829, in convert_xml_import obj.parse(doc.getroot()) File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 749, in parse self._tag_root(de) File "/opt/odoo/custom/src/odoo/odoo/tools/convert.py", line 709, in _tag_root raise ParseError(msg) from None # Restart with "--log-handler odoo.tools.convert:DEBUG" for complete traceback odoo.tools.convert.ParseError: while parsing /opt/odoo/auto/addons/purchase_operating_unit/views/purchase_order_view.xml:16 Error while validating view near: <form string="Purchase Order" class="o_purchase_order" __validate__="1"> <header> <button name="action_rfq_send" states="draft" string="Send by Email" type="object" context="{'send_rfq':True}" class="oe_highlight" data-hotkey="g"/> Field 'operating_unit_id' used in context ({'default_state': 'draft', 'default_operating_unit_id': operating_unit_id}) is restricted to the group(s) operating_unit.group_multi_operating_unit. View error context: {'file': '/opt/odoo/auto/addons/purchase_operating_unit/views/purchase_order_view.xml', 'line': 1, 'name': 'purchase_order_form', 'view': ir.ui.view(1036,), 'view.model': 'purchase.order', 'view.parent': ir.ui.view(979,), 'xmlid': 'purchase_order_form'}
问题原因
Odoo 16加强了视图上下文的权限验证:当在视图上下文中引用被权限组限制的字段时,即使视图中已添加该字段的权限组,上下文的引用仍会被拦截——因为上下文表达式在视图渲染时会被全局验证,不区分当前用户是否拥有对应权限组。
解决办法
方案1:模型层计算字段传递默认值(推荐)
在purchase.order模型中添加无权限限制的计算字段,封装权限判断逻辑:
from odoo import models, fields class PurchaseOrder(models.Model): _inherit = 'purchase.order' ou_default_for_lines = fields.Many2one('operating.unit', compute='_compute_ou_default_for_lines') def _compute_ou_default_for_lines(self): for rec in self: rec.ou_default_for_lines = rec.operating_unit_id if self.env.user.has_group('operating_unit.group_multi_operating_unit') else False
修改视图上下文引用该计算字段:
<field name="order_line" position="attributes"> <attribute name="context">{"default_state": "draft", "default_operating_unit_id": ou_default_for_lines}</attribute> </field>
方案2:上下文直接加入权限判断
无需修改模型,直接在上下文表达式中加入权限组判断:
<field name="order_line" position="attributes"> <attribute name="context">{"default_state": "draft", "default_operating_unit_id": env.user.has_group('operating_unit.group_multi_operating_unit') and operating_unit_id or False}</attribute> </field>
注意事项
- 方案1符合Odoo MVC架构,逻辑封装在模型层,更易维护;
- 方案2实现快捷,适合快速修复场景;
- 两种方案均保留
operating_unit_id字段的权限组限制,同时绕过视图验证。
内容的提问来源于stack exchange,提问作者Tiago Rangel
相关产品推荐
相关产品推荐

