如何根据Many2one字段值动态变更Odoo的One2many关联模型?
实现Odoo One2many字段关联模型随Many2one动态切换
嘿,这个需求完全能实现!不过得先明确一个Odoo的核心限制:字段定义本身是静态的,没法直接在运行时修改One2many的关联模型。但咱们可以换个思路,用api.onchange配合视图动态渲染的方式来搞定,下面给你一步步拆解:
1. 模型层:用抽象模型统一关联
首先,咱们需要让所有可能的子模型(比如你提到的mod.x_fields的不同变体)继承同一个抽象模型,这样主模型的One2many字段可以绑定到这个抽象模型,作为通用关联入口。同时给mod.items添加一个字段,用来存储每个Item对应的具体子模型:
from odoo import models, fields, api class ModItems(models.Model): _name = 'mod.items' _description = 'Items' name = fields.Char(required=True, string="Item Name") # 存储当前Item对应的子模型(比如mod.x_fields_a、mod.x_fields_b) associated_model = fields.Many2one('ir.model', string="Associated Characteristic Model", required=True) class ModBaseCharacteristics(models.AbstractModel): _name = 'mod.base.characteristics' _description = 'Base Model for Item Characteristics' # 关联到主模型的外键,所有子模型都需要这个字段 main_model_id = fields.Many2one('your.main.model', string="Main Record") # 示例子模型A class ModXFieldsA(models.Model): _name = 'mod.x_fields_a' _inherit = 'mod.base.characteristics' _description = 'Item A Characteristics' # 自定义字段 color = fields.Char(string="Color") size = fields.Integer(string="Size") # 示例子模型B class ModXFieldsB(models.Model): _name = 'mod.x_fields_b' _inherit = 'mod.base.characteristics' _description = 'Item B Characteristics' # 自定义字段 weight = fields.Float(string="Weight (kg)") material = fields.Selection([('plastic', 'Plastic'), ('metal', 'Metal')], string="Material") # 你的主模型 class YourMainModel(models.Model): _name = 'your.main.model' _description = 'Main Model' i_name = fields.Many2one('mod.items', string="Item", required=True) # 绑定到抽象模型作为通用入口 i_fields = fields.One2many('mod.base.characteristics', 'main_model_id', string="Item Characteristics")
2. 用api.onchange处理动态切换逻辑
在主模型里添加onchange方法,当用户切换i_name(选中不同Item)时:
- 清空之前的特性记录(避免不同模型的记录混在一起)
- 将当前Item对应的子模型信息传递到视图上下文,让视图知道该渲染哪个子模型的内容
@api.onchange('i_name') def _onchange_item_selection(self): if self.i_name: # 清空现有特性记录 self.i_fields = [(5, 0, 0)] # 传递子模型的标识到上下文 return { 'context': { 'target_model': self.i_name.associated_model.model, 'target_model_id': self.i_name.associated_model.id } } else: self.i_fields = [(5, 0, 0)] return {'context': {'target_model': False}}
3. 视图层:动态渲染对应子模型的字段
在主模型的表单视图中,给i_fields的One2many字段添加动态视图逻辑,根据上下文里的target_model来显示对应子模型的字段和操作按钮:
<odoo> <record id="view_main_model_form" model="ir.ui.view"> <field name="name">your.main.model.form</field> <field name="model">your.main.model</field> <field name="arch" type="xml"> <form string="Main Record"> <sheet> <group> <field name="i_name"/> <!-- 动态渲染特性字段 --> <field name="i_fields" attrs="{'invisible': [('i_name', '=', False)]}"> <tree string="Item Characteristics"> <field name="main_model_id" invisible="1"/> <!-- 根据目标模型显示对应字段 --> <t t-if="context.get('target_model') == 'mod.x_fields_a'"> <field name="color"/> <field name="size"/> </t> <t t-if="context.get('target_model') == 'mod.x_fields_b'"> <field name="weight"/> <field name="material"/> </t> <!-- 动态添加创建按钮 --> <button name="%(mod.x_fields_a.action_x_fields_a)d" type="action" string="Add A Characteristic" attrs="{'invisible': [('context', 'not in', {'target_model': 'mod.x_fields_a'})]}"/> <button name="%(mod.x_fields_b.action_x_fields_b)d" type="action" string="Add B Characteristic" attrs="{'invisible': [('context', 'not in', {'target_model': 'mod.x_fields_b'})]}"/> </tree> <form string="Characteristic Detail"> <field name="main_model_id" invisible="1"/> <t t-if="context.get('target_model') == 'mod.x_fields_a'"> <field name="color"/> <field name="size"/> </t> <t t-if="context.get('target_model') == 'mod.x_fields_b'"> <field name="weight"/> <field name="material"/> </t> </form> </field> </group> </sheet> </form> </field> </record> </odoo>
关键注意事项
- 确保每个子模型都有对应的
action(用来打开创建表单),这样动态添加按钮才能正常工作 - 抽象模型只需要定义通用字段,子模型负责添加各自的特性字段
onchange里清空旧数据很重要,否则不同模型的记录会混在i_fields里导致报错
总结一下:完全可以通过api.onchange配合抽象模型+动态视图的方式实现需求,核心是用抽象模型作为统一关联入口,再通过上下文传递动态模型信息,让视图渲染对应内容。
内容的提问来源于stack exchange,提问作者p.ry
相关产品推荐
相关产品推荐

