Odoo模型与视图委托继承的正确实现及冲突解决
问题
我开发了一个自定义模块,通过partner_id字段以委托继承方式继承res.partner模型,代码如下:
from odoo import fields, models class CustomModel(models.Model): _name = 'custom.model' _inherits = {'res.partner': 'partner_id'} _description = 'Custom Model' partner_id = fields.Many2one( comodel_name = 'res.partner', ondelete = 'restrict', required = True, auto_join = True, index = True, )
其表单视图以primary模式继承基础伙伴表单视图,代码如下:
<record id="custom_model_view_form" model="ir.ui.view"> <field name="model">custom.model</field> <field name="inherit_id" ref="base.view_partner_form"/> <field name="mode">primary</field> <field name="priority">20</field> <field name="arch" type="xml"> <!-- customizations in here --> </field> </record>
原本一切正常,但安装website_slides模块后,该模块给res.partner表单添加了自定义按钮/动作,现在每次更新自定义模块都会报错:action_view_courses is not a valid action on custom.model。我尝试调整视图优先级但无效,请问如何正确定义以避免此类冲突,且无需为自定义模型添加伪动作?
解决方案
方法1:重构视图,避免全盘继承res.partner的视图扩展
将视图的mode从primary改为extension,或者直接抛弃对base.view_partner_form的继承,重新构建custom.model的表单视图,只包含需要的res.partner字段和自定义内容:
<record id="custom_model_view_form" model="ir.ui.view"> <field name="model">custom.model</field> <field name="arch" type="xml"> <form> <sheet> <div class="oe_title"> <h1><field name="name"/></h1> </div> <group> <field name="email"/> <field name="phone"/> <!-- 按需添加其他res.partner核心字段 --> </group> <!-- 此处添加自定义模块的字段和布局 --> </sheet> </form> </field> </record>
这种方式彻底切断了与res.partner视图扩展的关联,自然不会引入website_slides添加的冲突动作按钮。
方法2:在继承视图中移除冲突按钮
如果要保留视图继承模式,可通过XPath定位并移除website_slides添加的action_view_courses按钮:
<record id="custom_model_view_form" model="ir.ui.view"> <field name="model">custom.model</field> <field name="inherit_id" ref="base.view_partner_form"/> <field name="mode">primary</field> <field name="priority">20</field> <field name="arch" type="xml"> <!-- 移除冲突的课程动作按钮 --> <xpath expr="//button[@name='action_view_courses']" position="replace"/> <!-- 自定义内容保留在这里 --> </field> </record>
直接在视图层面剔除不属于当前模型的动作,从根源解决报错。
方法3:模型层代理冲突动作(不推荐)
若不想修改视图,可在custom.model中添加代理方法,将冲突动作转发至关联的partner_id:
def action_view_courses(self): return self.partner_id.action_view_courses()
但此方法需为每个冲突动作单独添加代理,维护成本高,仅作为备选方案。
内容的提问来源于stack exchange,提问作者qdev
相关产品推荐
相关产品推荐

