先说结论
很多 Odoo 模型定制之所以越改越乱,不是因为不会 override,而是因为没想清楚:
- 创建时该做什么
- 修改时该做什么
- 复制时又该做什么
create()、write()、copy() 看起来都像“对象发生了变化”,但它们代表的是完全不同的生命周期入口。
这几个入口如果不分工,后面非常容易:
- 重复逻辑
- 边界错位
- 复制出脏数据
- 修改时触发不该触发的动作
create() 真正关心的是什么
create() 最核心关心的是:
一条业务对象第一次进入系统时,应该如何建立。
它适合处理:
- 初始字段补全
- 新建时的基础校验
- 首次生成某些关联对象
- 建立对象出生时就该有的结构
也就是说,create 关心的是“出生逻辑”。
write() 真正关心的是什么
write() 更像:
已有对象被修改时,系统该怎样响应这次变更。
它适合处理:
- 状态变化后的联动
- 字段变更后的同步逻辑
- 修改时的约束保护
- 某些更新后的后续动作
所以 write 不是“create 的第二版”,它处理的是对象已经存在之后的变化。
copy() 为什么经常被低估
因为很多人会想:复制不就是创建一条新记录吗?
技术上它最终确实会变成新对象。
但业务语义完全不一样。
copy() 真正关心的是:
当一个对象被拿来当模板复用时,哪些值应该继承,哪些值必须重置,哪些业务痕迹绝不能带过去。
这和普通 create 差别很大。
为什么复制逻辑特别容易出脏数据
因为“复制可见字段”并不等于“复制业务语义”。
很多对象里会有这些东西:
- 状态
- 编号
- 追踪记录
- 已完成动作
- 下游关联
- 统计结果
这些内容如果跟着复制过去,往往会直接污染新对象。
所以 copy 的真正难点不是复制本身,而是:
- 哪些该带,哪些不该带。
为什么很多逻辑不该同时塞进 create 和 write
因为它们的语境不一样。
有些事情只应该在对象第一次出生时发生; 有些事情只应该在后续更新时发生; 如果两个入口都塞,就可能变成:
- 新建时重复触发
- 修改时误触发初始化逻辑
- 维护者根本看不懂真正边界
所以生命周期入口最重要的,不是 override 本身,而是边界感。
一个特别实用的判断方法
写逻辑前先问:
1. 这是对象“出生时”才该发生的吗?
如果是,更接近 create。
2. 这是“已有对象变化后”的响应吗?
如果是,更接近 write。
3. 这是“从旧对象派生新对象”时的继承策略吗?
如果是,更接近 copy。
只要先把这三件事分开,很多代码结构会自然清楚。
实战里最容易踩的 5 个坑
1. create 和 write 里放同一套逻辑
边界会越来越糊。
2. copy 不重置状态、编号、痕迹字段
最容易复制出脏数据。
3. 把“首次初始化”逻辑放进 write
后续更新会不断误触发。
4. 把“变更响应”逻辑只放 create
后来对象修改时行为不一致。
5. 只从技术复用角度写,不从业务生命周期角度写
这类代码一开始省事,后面最难维护。
一句话记忆法
把它们记成一句话:
create 管对象出生,write 管对象变化,copy 管对象派生;它们都在改数据,但负责的生命周期阶段完全不同。
理解这一句,Odoo 模型入口设计会清楚很多。
DISCUSSION
评论区