先说结论
在 Odoo 里,扩展已有 Selection 字段时,真正安全的思路通常不是整段重写,而是:
- 用
selection_add扩展已有选项 - 用
ondelete说明这个新增选项未来失效时怎么办
也就是说,selection_add 解决的是怎么加新值,ondelete 解决的是以后不想要这个值时怎么收场。
为什么直接重写 selection 很危险
因为你扩展的往往不是你自己独占的字段。
很多 Selection 字段来自:
- 基础模块
- 别的官方模块
- 第三方模块
- 未来还可能继续被别的模块扩展
如果你直接整段覆盖,风险是:
- 把别人的选项覆盖掉
- 升级后官方新增选项丢失
- 多模块同时继承时顺序变脆
所以官方源码也明确提示:如果只是扩展已有选项,优先使用 selection_add。
selection_add 真正在表达什么
它表达的是:
不要推翻原来的选择集合,只是在现有集合上追加或插入新的业务值。
这和 _inherit 的整体设计哲学是一致的:优先扩展,不轻易重写,尽量保持兼容。
为什么 ondelete 不是可有可无的小参数
它解决的是一个非常现实的问题:
如果你这个模块以后卸载了,或者你新增的 selection 选项以后被移除了,那历史数据怎么办?
假设你给某状态字段加了一个新值:custom_review。
如果某天这个值不再存在,系统就必须知道:
- 设为空?
- 改回默认值?
- 改成另一个安全值?
- 直接删记录?
- 用自定义逻辑迁移?
ondelete 说的就是这个“退场策略”。
官方源码给你的核心启发
在 fields_selection.py 里,官方把 ondelete 描述得很明确:
set nullcascadeset defaultset VALUE- 或者 callable
这说明 Odoo 并不是把 Selection 当成纯前端下拉框,而是当成一种会沉淀到历史数据里的业务状态值。
新手最容易踩的 4 个坑
1. 只加新值,不想退场策略
开发阶段觉得没问题,后面模块卸载、状态废弃、升级清理时就开始痛。
2. 用整段 selection 覆盖而不是 selection_add
短期能跑,长期兼容性很差。
3. 把 Selection 当成随便加几个字符串
其实每个值背后都可能对应:
- 视图状态
- 按钮条件
- 权限边界
- 业务流程分支
- 历史数据语义
4. ondelete 选错策略
比如本来应该 set default,你却用 cascade,那代价可能非常大。
一句话记忆法
selection_add决定怎么把新状态接进来,ondelete决定这个状态以后退场时怎么不把数据搞坏。
DISCUSSION
评论区