You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 09:06:01