Odoo v13自定义模块迁移至v16:空向导安装报错问题
Odoo v13自定义模块迁移至v16空向导安装ParseError问题
问题描述
将原Odoo v13开发的自定义模块迁移到v16环境时,即使是结构与官方插件一致的空向导,安装过程仍触发ParseError。已将向导定义精简至最小内容,错误依旧;注释其他模型视图中调用该向导的按钮后,模块可正常安装。
相关代码
向导XML定义
<record id="my_custom_wizard_form" model="ir.ui.view"> <field name="name">my.custom.wizard.form</field> <field name="model">my.custom.wizard</field> <field name='arch' type='xml'> <form string='My Wizard'> <sheet> </sheet> <footer> </footer> </form> </field> </record> <record id="act_my_custom_wizard" model="ir.actions.act_window"> <field name="name">My Custom Wizard</field> <field name="res_model">my.custom.wizard</field> <field name="view_mode">form</field> <field name="target">new</field> <field name="view_id" ref="my_custom_wizard_form"/> <!--field name="binding_model_id" eval="False"/--> </record> <menuitem id="menu_my_custom_wizard" action="act_my_custom_wizard" parent="my_configration" sequence="2"/>
向导调用Python代码
class mymodel(models.Model): _name = "my.model" #... #... def open_brevo_import_wizard(self): return { 'type': 'ir.actions.act_window', 'res_model': 'my.custom.wizard', 'view_mode': 'form', 'target': 'new', }
触发报错的按钮视图
<record id="myothermodel_list_view_form" model="ir.ui.view"> <field name="name">list_view_form</field> <field name="model">myothermodel.list</field> <field name="type">form</field> <field name="arch" type="xml"> <form string="List"> <sheet> <group> <button type="object" name="open_mycustom_wizard" string="open mycuston wizard" class="oe_button oe_form_button oe_highlight"/> </group> </sheet> </form> </field> </record>
报错信息
**File "/home/odoo/src/odoo/odoo/tools/convert.py", line 711, in _tag_root raise ParseError('while parsing %s:%s, somewhere inside\n%s' % ( odoo.tools.convert.ParseError: while parsing /home/odoo/src/user/my_custom_module_zsb/wizard/my_custom_wizard.xml:3, somewhere inside**
完整报错栈
Failed to load registry Traceback (most recent call last): File "/home/odoo/src/odoo/odoo/tools/convert.py", line 698, in _tag_root f(rec) File "/home/odoo/src/odoo/odoo/tools/convert.py", line 599, in _tag_record record = model._load_records([data], self.mode == 'update') File "/home/odoo/src/odoo/odoo/models.py", line 4364, in _load_records data['record']._load_records_write(data['values']) File "/home/odoo/src/odoo/odoo/addons/base/models/ir_ui_view.py", line 2218, in _load_records_write super(View, self)._load_records_write(values) File "/home/odoo/src/odoo/odoo/models.py", line 4295, in _load_records_write self.write(values) File "/home/odoo/src/odoo/addons/website/models/theme_models.py", line 385, in write res = super(IrUiView, other_views).write(vals) File "/home/odoo/src/odoo/addons/website/models/ir_ui_view.py", line 93, in write return super(View, self).write(vals) File "/home/odoo/src/enterprise/web_studio/models/studio_mixin.py", line 33, in write res = super(StudioMixin, self).write(vals) File "/home/odoo/src/odoo/odoo/addons/base/models/ir_ui_view.py", line 573, in write res = super(View, self).write(self._compute_defaults(vals)) File "/home/odoo/src/odoo/odoo/models.py", line 3787, in write fields[0].determine_inverse(real_recs) File "/home/odoo/src/odoo/odoo/fields.py", line 1396, in determine_inverse determine(self.inverse, records) File "/home/odoo/src/odoo/odoo/fields.py", line 97, in determine return needle(*args) File "/home/odoo/src/odoo/odoo/addons/base/models/ir_ui_view.py", line 340, in _inverse_arch view.write(data) File "/home/odoo/src/odoo/addons/website/models/theme_models.py", line 385, in write res = super(IrUiView, other_views).write(vals) File "/home/odoo/src/odoo/addons/website/models/ir_ui_view.py", line 93, in write return super(View, self).write(vals) File "/home/odoo/src/enterprise/web_studio/models/studio_mixin.py", line 33, in write res = super(StudioMixin, self).write(vals) File "/home/odoo/src/odoo/odoo/addons/base/models/ir_ui_view.py", line 573, in write res = super(View, self).write(self._compute_defaults(vals)) File "/home/odoo/src/odoo/odoo/models.py", line 3755, in write field.write(self, value) File "/home/odoo/src/odoo/odoo/fields.py", line 1815, in write text2terms[self.get_text_content(term)].append(term) File "/home/odoo/src/odoo/odoo/fields.py", line 1681, in get_text_content return func(term) File "/home/odoo/src/odoo/odoo/tools/translate.py", line 361, in get_text_content content = html.fromstring(term).text_content() File "/usr/lib/python3/dist-packages/lxml/html/__init__.py", line 875, in fromstring doc = document_fromstring(html, parser=parser, base_url=base_url, **kw) File "/usr/lib/python3/dist-packages/lxml/html/__init__.py", line 763, in document_fromstring raise etree.ParserError( lxml.etree.ParserError: Document is empty The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/home/odoo/src/odoo/odoo/modules/registry.py", line 90, in new odoo.modules.load_modules(registry, force_demo, status, update_module) File "/home/odoo/src/odoo/odoo/modules/loading.py", line 484, in load_modules processed_modules += load_marked_modules(cr, graph, File "/home/odoo/src/odoo/odoo/modules/loading.py", line 372, in load_marked_modules loaded, processed = load_module_graph( File "/home/odoo/src/odoo/odoo/modules/loading.py", line 231, in load_module_graph load_data(cr, idref, mode, kind='data', package=package) File "/home/odoo/src/odoo/odoo/modules/loading.py", line 71, in load_data tools.convert_file(cr, package.name, filename, idref, mode, noupdate, kind) File "/home/odoo/src/odoo/odoo/tools/convert.py", line 763, in convert_file convert_xml_import(cr, module, fp, idref, mode, noupdate) File "/home/odoo/src/odoo/odoo/tools/convert.py", line 829, in convert_xml_import obj.parse(doc.getroot()) File "/home/odoo/src/odoo/odoo/tools/convert.py", line 749, in parse self._tag_root(de) File "/home/odoo/src/odoo/odoo/tools/convert.py", line 711, in _tag_root raise ParseError('while parsing %s:%s, somewhere inside\n%s' % ( odoo.tools.convert.ParseError: while parsing /home/odoo/src/user/my_custom_module_zsb/wizard/my_custom_wizard.xml:3, somewhere inside <record id="my_custom_wizard_form" model="ir.ui.view"> <field name="name">my.custom.wizard.form</field> <field name="model">my.custom.wizard</field> <field name='arch' type='xml'> <form string='My Wizard'> <sheet> </sheet> <footer> </footer> </form> </field> </record>
解决方案
从报错栈可以看到,根源是lxml.etree.ParserError: Document is empty,这是因为Odoo v16在解析视图的翻译文本时,会尝试提取<sheet>和<footer>标签内的内容,空标签会被视为空文档导致解析失败。
修改向导的XML视图,在<sheet>或<footer>中添加至少一个有效元素即可解决问题,比如:
修改后的向导XML定义
<record id="my_custom_wizard_form" model="ir.ui.view"> <field name="name">my.custom.wizard.form</field> <field name="model">my.custom.wizard</field> <field name='arch' type='xml'> <form string='My Wizard'> <sheet> <!-- 添加空group避免空文档解析错误 --> <group/> </sheet> <footer> <!-- 添加取消按钮,同时避免footer为空 --> <button type="object" name="cancel" string="Cancel" class="btn-secondary"/> </footer> </form> </field> </record>
补充说明
- 在
<sheet>中添加空的<group/>标签,或者任意可见/隐藏的字段、元素,都能避免空文档问题。 - 如果不需要按钮,也可以在
<footer>中添加一个隐藏的元素,比如<div style="display:none"/>,但推荐保留基础交互按钮以符合Odoo界面规范。 - Odoo v13对空视图标签的解析限制更宽松,v16因翻译模块的文本提取逻辑优化,导致空标签触发解析错误。
内容的提问来源于stack exchange,提问作者Ahrimann Steiner
相关产品推荐
相关产品推荐

