我们在odoo中构建业务系统模块的时候,通常会使用one2many、many2one或many2many将模型进行关联,由此产生的数据也会通过外键发生关联。那么在odoo中删除数据的时候,如何关联删除呢?接下来我们以初学者的视角来观察下这一过程。
刚开始接触odoo,可能时不时的就会感叹odoo的低代码魅力:"这么少的代码,这么强悍的功能"。即便是一个主从模型的功能,很快也就完事了。正沉浸在这种喜悦中的时候,突然一个弹框提示:
目前构建的代码涉及到两个菜单功能,运单管理和承运管理,业务场景是这样的:
- 运单管理用于创建要运送的货物的基本信息和明细信息,包括主表[waybill]和明细表[waybill_detail]
- 承运管理也是一个主附表关系,主表[shipping_document]用来记录车辆、司机、运费等基本信息,附表[shiping_document_detail]用来记录要承运的运单信息
- 现在要删除运单表的信息,但是提示需要把承运明细表[shiping_document_detail]中的数据删除;问题是承运管理中的数据已经删除过了,用动态图来说明下:
既然提示说需要删除承运明细表[shiping_document_detail]中的数据,在管理界面中已经删除过看不到数据了,我们不妨到数据表中看下:
原来在数据库中并没有把数据删除掉,只是把承运主表[shipping_document]的关联id删除了,如上图标记1所示。如果此时我删除运单表[waybill]中的数据,在承运明细表[shipping_document_detail]中依然有和运单相关的残留数据,如上图标记2所示。这在odoo看来是不可接受的,所以就抛出了验证错误提示。要避免这样的验证错误提示发生,我们就需要在删除承运主表[shipping_document]数据的时候,将承运明细表[shipping_document_detail]中的关联数据也删除掉。接下来我们就来说下odoo中的级联删除操作:
ondelete='cascade'
ondelete是odoo在模型中引入的一种触发机制,在odoo16源码中,目前只有Selection和Many2one这两种字段类型支持传参调用,我们看下ondelete在Many2one类型中的定义:
通过上图我们了解到,ondelete的功能就是在参考模型中的记录被删除的时候,做一些操作。可以有'set null'、'restrict'、'cascade'这些操作,现在我们主要介绍cascade。我们在承运明细表[shipping_document_detail]的关联字段shipping_document_id上添加ondelete='cascade':
1 class ShippingDocumentDetail(models.Model):
2 _name = 'shipping.document.detail'
3 _description = 'Shipping Document Detail'
4
5 waybill_id = fields.Many2one('waybill', required=True, domain="[('destination', '=', destination_id)]")
6 receiver_id = fields.Many2one(related='waybill_id.receiver_id', readonly=True)
7 receiver_tel = fields.Char(string="Consignee Phone", store=False, readonly=True, compute="_compute_customerInfo")
8 detail_ids = fields.One2many(related='waybill_id.detail_ids')
9 total_fees = fields.Float(related='waybill_id.total_fees')
10 shipping_document_id = fields.Many2one('shipping.document', string='Shipping Document',ondelete='cascade')
11 destination_id=fields.Integer(string='Destination Id', compute="_compute_destination_id")
模块升级后,我们先手动删除承运明细表[shipping_document_detail]中的残留数据,然后添加新的测试数据,我们添加的承运单截图如下:
数据库中对应截图如下:
接下来我们执行承运单的删除操作,再查询数据库的时候,发现刚才创建的数据已经没有了。
写这篇博客的时候,我已经整理好了文章大纲,边写边测试验证,最后发现我原来的理解是错的,原来的大纲中还有在One2many中使用ondelete='cascade',以及ondelete='cascade'无法解决问题时如何通过unlink()来解决。唉,半路借来的内容真是害人不轻。还好写了博客,又参考odoo官方文档和源码走了一遍流程;不仅深入的理解了这个知识点,也优化了一知半解的时候写的代码。
源码地址【源码更新会有3-5天的时间出入】:github
点击链接阅读原文:菜园工程师