Odoo 13:如何在on_change方法中调用向导并实现字段值回传?
解决Odoo字段变化时弹出向导并传递数据的问题
你的思路方向是对的,但Odoo的@api.onchange方法在返回ir.actions.act_window时,前端的处理逻辑有局限(尤其是Odoo 13+版本),直接返回窗口动作通常不会触发弹窗。下面是更可靠的实现方案,完美匹配你的核心需求:
核心思路
通过onchange触发一个带操作按钮的警告提示,用户点击按钮后打开向导;向导接收原记录的ID,输入数据后再回写到原记录中。这种方式是Odoo官方推荐的交互模式,避免了前端的限制。
具体实现步骤
1. 修改原模型的onchange方法
在你的业务模型中,修改on_change方法,返回包含向导触发按钮的警告:
import json from odoo import models, fields, api class YourModel(models.Model): _name = 'your.model.name' # 替换为你的模型名 _description = 'Your Model' my_field = fields.Char(string="触发字段") target_field = fields.Char(string="接收数据的字段") # 替换为你要更新的字段 @api.onchange('my_field') def on_change(self): if self.my_field: # 仅当字段有值变化时触发 # 获取预定义的向导动作 wizard_action = self.env.ref('my_module.action_open_my_wizard').read()[0] # 传递当前记录ID到向导的context中 wizard_action['context'] = {'default_active_id': self.id} # 将动作序列化为前端可识别的字符串 action_str = json.dumps(wizard_action) return { 'warning': { 'title': "请补充信息", 'message': "需要您输入相关数据,请点击下方按钮打开向导:", 'buttons': [ { 'text': '打开数据输入向导', 'type': 'action', 'action': action_str, } ] } }
2. 创建向导模型
新增一个瞬态模型(TransientModel)作为弹窗载体,负责接收用户输入并更新原记录:
from odoo import models, fields, api class MyWizard(models.TransientModel): _name = 'my.wizard' _description = '数据输入向导' active_id = fields.Many2one('your.model.name', string="关联记录", readonly=True) my_field2 = fields.Char(string="需要输入的数据", required=True) def save_and_close(self): """保存数据到原记录并关闭向导""" if self.active_id: # 将输入的值写入原记录的目标字段 self.active_id.write({'target_field': self.my_field2}) # 返回关闭窗口的动作 return {'type': 'ir.actions.act_window_close'}
3. 配置向导的视图和动作
在模块的XML文件中定义向导的表单视图和打开动作:
<odoo> <!-- 向导表单视图 --> <record id="view_my_wizard_form" model="ir.ui.view"> <field name="name">my.wizard.form.view</field> <field name="model">my.wizard</field> <field name="arch" type="xml"> <form string="输入数据"> <group> <!-- 隐藏关联字段,仅用于传递记录ID --> <field name="active_id" invisible="1"/> <field name="my_field2" placeholder="请输入数据..."/> </group> <footer> <button name="save_and_close" type="object" string="保存" class="btn-primary"/> <button string="取消" class="btn-secondary" special="cancel"/> </footer> </form> </field> </record> <!-- 打开向导的动作 --> <record id="action_open_my_wizard" model="ir.actions.act_window"> <field name="name">打开数据输入向导</field> <field name="res_model">my.wizard</field> <field name="view_mode">form</field> <field name="target">new</field> <!-- 弹窗模式 --> </record> </odoo>
4. 模块配置
确保在__manifest__.py中添加了向导的Python文件和XML视图文件:
{ # ... 其他配置项 'data': [ # ... 其他视图 'views/my_wizard_view.xml', ], 'depends': ['base'], }
关键说明
- 为什么不用直接返回动作?Odoo的
onchange事件主要设计用于字段更新和即时提示,前端不会处理返回的窗口动作;而警告框中的按钮是官方支持的交互方式,兼容性更好。 - 如何传递原记录ID?通过
context的default_active_id参数,向导初始化时会自动填充关联字段,后续就能直接操作原记录。 - 瞬态模型的优势:
TransientModel的数据会定期清理,适合这种一次性的临时交互场景。
内容的提问来源于stack exchange,提问作者Raihan
相关产品推荐
相关产品推荐

