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

Odoo 10筛选后删除关联记录异常:全部关联记录被误删

解决Odoo自定义表单中One2Many筛选后删除导致全部记录丢失的问题

这个问题我之前踩过坑!核心原因是Odoo处理One2Many字段的机制:当你提交表单时,前端只会把当前可见的One2Many记录数据传给后端。那些被筛选隐藏的记录,因为没出现在提交的表单数据里,后端会默认把它们标记为「需要删除」,哪怕你根本没碰过它们。

为什么会这样?

Odoo的One2Many字段是通过一组操作指令来同步数据的,比如:

  • (2, id):删除指定ID的记录
  • (4, id):关联已存在的记录
  • 如果你提交的指令里没有包含某个已关联的One2Many记录ID,后端就会认为你要解除它的关联(甚至删除,取决于字段的ondelete设置)。当你筛选后只操作可见记录时,隐藏的记录自然不会出现在提交指令里,结果就被误删了。

几个可行的解决方案

1. 临时应急方案:取消筛选后再操作

如果只是临时处理,最简单的办法就是删除前先取消One2Many列表的筛选,让所有记录都显示出来,再找到要删除的那条操作。这样提交时所有记录都会被包含,不会被误删。但这只是治标不治本,用户体验也不好。

2. 前端层面:修改组件逻辑,确保提交时包含所有有效记录

你可以自定义One2Many字段的前端组件,在表单提交前自动取消筛选,让所有未被删除的记录都回到视图中,再触发提交。比如重写FieldOne2Many的保存相关方法:

odoo.define('your_module.one2many_fix', function(require) {
    "use strict";

    var FieldOne2Many = require('web.relational_fields').FieldOne2Many;

    FieldOne2Many.include({
        _onSave: function () {
            // 先取消当前列表的筛选
            if (this.listController) {
                this.listController.searchView.clear();
            }
            // 再执行原有的保存逻辑
            this._super.apply(this, arguments);
        }
    });
});

这个方法能保证提交时所有记录都被包含,但需要你有前端开发的基础。

3. 后端层面:重写父模型的write方法,过滤误删逻辑

最稳妥的办法是在后端控制数据同步逻辑,只删除那些明确标记要删除的记录,忽略那些因为筛选没被提交的记录。比如重写Model A的write方法:

from odoo import models, api

class ModelA(models.Model):
    _inherit = 'model.a'  # 替换成你的父模型技术名称

    @api.multi
    def write(self, vals):
        # 只处理One2Many字段b_ids的情况
        if 'b_ids' in vals:
            # 拆分操作指令:提取明确要删除的记录ID,保留其他操作
            delete_ids = []
            valid_operations = []
            for op in vals['b_ids']:
                # Odoo的One2Many操作格式:(操作码, ID, 数据)
                if op[0] == 2:  # 2是删除操作
                    delete_ids.append(op[1])
                else:
                    valid_operations.append(op)
            
            # 获取当前模型中所有未被明确删除的B记录ID
            remaining_b_ids = self.b_ids.filtered(lambda b: b.id not in delete_ids).ids
            
            # 把这些剩余的记录添加到操作指令里,确保后端不会误删
            for b_id in remaining_b_ids:
                # 检查是否已经在操作指令中,避免重复添加
                exists = any(op[0] == 4 and op[1] == b_id for op in valid_operations)
                if not exists:
                    valid_operations.append((4, b_id))
            
            # 替换原有的b_ids操作指令
            vals['b_ids'] = valid_operations
        
        # 执行父类的write方法
        return super(ModelA, self).write(vals)

这个方法从根源上避免了误删,不管前端有没有筛选,后端只会处理你明确要删除的记录,其他记录都会被保留。

注意事项

  • 如果你用的是Odoo 14+,@api.multi可以换成@api.model,根据版本调整语法。
  • 测试时要注意One2Many字段的ondelete设置,如果是cascade,可能需要额外处理,但上面的代码已经覆盖了大部分场景。

内容的提问来源于stack exchange,提问作者Cuu Nguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:35:42