
1. 为什么需要自定义消息弹框在Odoo12开发过程中系统默认的消息提示机制存在几个明显的痛点。首先是样式问题使用raise抛出UserError或Warning时页面顶部会出现一个红色的Odoo Server Error提示条这种设计在正式业务场景中显得不够专业容易给用户造成系统出现严重错误的错觉。其次是功能限制当在Dialog对话框中触发系统默认提示时经常会出现表单数据丢失的情况。特别是在处理复杂表单时用户可能已经填写了大量数据一个简单的验证提示就导致所有输入内容清空这种体验对终端用户来说是灾难性的。最后是交互体验的不足。系统默认提示无法自定义按钮文本、无法添加确认回调函数、也不能灵活控制弹窗大小和位置。这些限制使得我们在处理重要操作确认、复杂表单验证等场景时显得捉襟见肘。2. 自定义消息弹框的实现原理2.1 TransientModel的基础作用自定义弹框的核心是继承models.TransientModel创建临时模型。与常规Model不同TransientModel的数据不会永久保存到数据库中而是在处理后自动清理。这种特性非常适合用于实现临时性的交互对话框。class MyMessageWizard(models.TransientModel): _name my.message.wizard message fields.Text(message, requiredTrue)2.2 窗口动作的触发机制当我们需要显示弹框时通过返回一个ir.actions.act_window动作来实现。关键参数包括view_mode: 设置为form表示以表单视图展示target: new表示在新窗口打开(实际效果是弹出对话框)res_id: 指定要显示的临时记录IDreturn { name: 提示, type: ir.actions.act_window, view_mode: form, res_model: my.message.wizard, res_id: message.id, target: new }2.3 视图布局的定制化通过XML视图定义我们可以完全控制弹框的展示样式。基础结构包含form标签定义整体表单field标签显示消息内容footer中的按钮定义用户操作form p field namemessage readonly1/ /p footer button nameaction_confirm string确认 typeobject default_focus1 classoe_highlight/ /footer /form3. 完整实现步骤详解3.1 创建消息向导模型在模块目录下新建my_message_wizard.py文件# -*- coding: utf-8 -*- from odoo import models, fields, api class MyMessageWizard(models.TransientModel): _name my.message.wizard _description Custom Message Wizard message fields.Text(消息内容, requiredTrue) secondary_message fields.Text(补充说明) # 新增的辅助消息字段 api.model def action_show_message(self, message, title系统提示): 快捷显示消息的类方法 wizard self.create({message: message}) return { name: title, type: ir.actions.act_window, view_mode: form, res_model: self._name, res_id: wizard.id, target: new, context: self.env.context, } def action_confirm(self): 确认按钮的回调方法 # 可以在这里添加确认后的处理逻辑 return {type: ir.actions.act_window_close}3.2 设计弹框视图在views目录下创建my_message_wizard.xmlodoo record idmy_message_wizard_form modelir.ui.view field namenamemy.message.wizard.form/field field namemodelmy.message.wizard/field field namearch typexml form string系统提示 sheet div classoe_title h1i classfa fa-exclamation-circle/ 重要提示/h1 /div group field namemessage readonly1 classoe_inline/ field namesecondary_message readonly1 attrs{invisible: [(secondary_message,,False)]}/ /group /sheet footer button nameaction_confirm string确认 typeobject classbtn-primary/ button string取消 specialcancel classbtn-secondary/ /footer /form /field /record /odoo3.3 注册文件到清单在__manifest__.py中添加依赖和视图文件{ name: Custom Message Wizard, version: 1.0, depends: [base], data: [ views/my_message_wizard.xml, ], }4. 高级应用与实战技巧4.1 动态控制弹框样式通过传递context参数可以实现弹框样式的动态控制# 在调用时传递样式参数 return { name: 警告, type: ir.actions.act_window, view_mode: form, res_model: my.message.wizard, res_id: message.id, target: new, context: { dialog_size: medium, # small/medium/large dialog_class: bg-warning, # 背景色类 } }然后在XML视图中通过t-if条件渲染不同样式div t-ifcontext.get(dialog_class) t-attf-classalert #{context.get(dialog_class)} !-- 内容 -- /div4.2 多按钮与回调处理扩展向导模型支持多个操作按钮def action_approve(self): # 批准逻辑 self.env.user.notify_success(操作已批准) return {type: ir.actions.act_window_close} def action_reject(self): # 拒绝逻辑 return { type: ir.actions.act_window, view_mode: form, res_model: reject.reason.wizard, # 另一个向导模型 target: new }对应视图添加多个按钮footer button nameaction_approve string批准 typeobject classbtn-success/ button nameaction_reject string拒绝 typeobject classbtn-danger/ button string取消 specialcancel classbtn-secondary/ /footer4.3 与前端JavaScript交互在按钮上添加JS事件处理button nameaction_confirm string确认 typeobject classoe_highlight attrs{data-action: custom_action}/然后通过扩展Widget实现前端交互odoo.define(my_module.CustomDialog, function(require) { use strict; var Widget require(web.Widget); var CustomDialog Widget.extend({ template: CustomDialogTemplate, events: { click button[data-action]: _onActionButtonClick, }, _onActionButtonClick: function(ev) { var $button $(ev.currentTarget); var action $button.data(action); // 自定义处理逻辑 } }); return CustomDialog; });5. 常见问题与解决方案5.1 表单数据丢失问题当在现有表单操作中触发弹框时可能会遇到表单数据丢失的情况。解决方案是确保在按钮点击处理中正确返回Actionapi.multi def button_show_message(self): # 先保存当前表单 self.ensure_one() self.write({state: pending}) # 再显示消息 return self.env[my.message.wizard].action_show_message(请确认操作)在向导模型中处理完成后重新打开原表单def action_confirm(self): # 获取原始记录ID original_id self.env.context.get(active_id) return { type: ir.actions.act_window, view_mode: form, res_model: original.model, res_id: original_id, target: current }5.2 多语言支持实现为了使消息弹框支持多语言在模型字段中使用翻译方法message fields.Text(string_(Message), requiredTrue)在XML视图中使用翻译标签h1i classfa fa-exclamation-circle/ t t-esc_(Important Notice)/ /h1调用时传递翻译后的消息message _(The record has been updated successfully) return self.env[my.message.wizard].action_show_message(message)5.3 性能优化建议避免在循环中频繁创建弹框应该收集所有验证错误后一次性显示。对于复杂表单考虑使用前端验证减少服务器交互// 在前端JS中先进行基础验证 if (!this.$(input[namename]).val()) { this.displayNotification({ title: _t(Error), message: _t(Name is required), type: danger }); return; }重用向导实例而不是频繁创建新实例api.model def get_message_wizard(self): # 查找或创建单例实例 wizard self.env[my.message.wizard].search([], limit1) if not wizard: wizard self.create({message: }) return wizard