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

如何根据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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:48:34