Odoo技术问询:取消/离开表单时如何删除已保存模型?
解决Odoo预约表单自动保存后取消/离开时删除记录的方案
嘿,这个场景我太熟悉了——Odoo的表单机制确实会在触发某些按钮动作时自动保存记录,哪怕用户只是想查个时段还没确定要预约。下面给你几个实用的解决思路,结合前端和后端逻辑,覆盖用户点击取消和直接关闭页面的情况:
1. 前端监听取消按钮+页面离开事件,主动删除记录
这是最直接的方式,针对用户明确点击“取消”或者直接关闭页面的情况,通过JavaScript调用Odoo的RPC接口删除当前记录。
步骤1:在表单视图中添加按钮和脚本
修改你的预约模型的form视图,添加取消按钮和自定义脚本:
<field name="arch" type="xml"> <form> <!-- 你的预约表单字段,比如姓名、联系方式等 --> <button name="action_check_availability" string="查询可用时段" type="object" class="btn-primary"/> <button name="action_cancel_reservation" string="取消" type="object" class="btn-secondary"/> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { // 获取当前记录的ID(Odoo保存后会生成这个ID) const recordId = odoo.__DEBUG__.models[0].res_id; // 监听取消按钮点击事件 const cancelBtn = document.querySelector('.btn-secondary[name="action_cancel_reservation"]'); if (cancelBtn) { cancelBtn.addEventListener('click', function(e) { if (recordId) { // 调用后端unlink方法删除记录 odoo.rpc({ model: 'your.reservation.model', // 替换成你的模型名 method: 'unlink', args: [[recordId]], }).then(() => { // 关闭表单或跳转到列表页 window.location.href = '/web#action=your_reservation_action_id'; // 替换成你的动作ID }); } }); } // 监听页面离开事件(比如用户直接关闭标签页) window.addEventListener('beforeunload', function(e) { if (recordId) { // 用同步RPC确保删除请求能执行完成 odoo.rpc({ model: 'your.reservation.model', method: 'unlink', args: [[recordId]], }, {async: false}); } }); }); </script> </form> </field>
步骤2:后端实现取消动作(可选)
你也可以直接在后端的取消按钮方法里处理删除,这样更符合Odoo的逻辑:
from odoo import models, fields class YourReservationModel(models.Model): _name = 'your.reservation.model' _description = '预约记录' # 你的字段定义 name = fields.Char('姓名') phone = fields.Char('手机号') # ...其他字段 def action_check_availability(self): # 你的查询可用时段逻辑,比如返回通知或更新字段 return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': '可用时段查询结果', 'message': '上午9:00、下午2:00有空', 'sticky': False, } } def action_cancel_reservation(self): # 删除当前记录 self.unlink() # 关闭表单 return { 'type': 'ir.actions.act_window_close', }
2. 后端定时任务兜底,清理未完成的草稿预约
有些用户可能直接关闭页面,前端的beforeunload事件可能因为浏览器限制没触发,这时候就需要后端定时任务来清理“废弃”的预约记录。
步骤1:给模型添加标记字段
给你的预约模型加一个草稿标记和创建时间字段:
from odoo import models, fields from datetime import timedelta class YourReservationModel(models.Model): _name = 'your.reservation.model' is_draft_reservation = fields.Boolean('草稿预约', default=True) create_date = fields.Datetime('创建时间', default=fields.Datetime.now) # ...其他字段和方法 def _cleanup_draft_reservations(self): # 清理创建超过10分钟的草稿预约(可根据需求调整时长) cutoff_time = fields.Datetime.now() - timedelta(minutes=10) draft_records = self.search([ ('is_draft_reservation', '=', True), ('create_date', '<=', cutoff_time) ]) draft_records.unlink()
步骤2:配置定时任务
在模块的data目录下创建ir_cron.xml文件,添加定时任务:
<?xml version="1.0" encoding="utf-8"?> <odoo> <record id="cron_cleanup_draft_reservations" model="ir.cron"> <field name="name">清理未完成的草稿预约</field> <field name="model_id" ref="model_your_reservation_model"/> <!-- 替换成你的模型引用 --> <field name="state">code</field> <field name="code">model._cleanup_draft_reservations()</field> <field name="interval_number">10</field> <!-- 每10分钟执行一次 --> <field name="interval_type">minutes</field> <field name="numbercall">-1</field> <!-- 无限次执行 --> <field name="active" eval="True"/> </record> </odoo>
记得在模块的__manifest__.py里把这个xml文件加到data列表中。
步骤3:用户完成预约时标记为非草稿
当用户确认预约(比如点击“提交预约”按钮)时,把is_draft_reservation设为False,这样定时任务就不会删除这条有效记录:
def action_confirm_reservation(self): self.write({'is_draft_reservation': False}) # 其他确认逻辑,比如发送通知等
注意事项
- 前端的
beforeunload事件中使用同步RPC是为了确保删除请求能在页面关闭前执行,但有些现代浏览器可能会限制同步请求,所以后端定时任务是必要的兜底方案。 - 如果你的表单是在弹窗中打开的,可能需要调整前端脚本的记录ID获取方式,比如通过Odoo的
web.FormController来获取当前记录。
内容的提问来源于stack exchange,提问作者Marcio Cruz




