先说结论
Odoo 默认值问题,最容易乱的地方不是语法,而是:
- 默认值从哪来
- 谁优先
- 当前 context 里到底带了什么
你只要先记住一句话:
Odoo 的默认值不是单点来源,而是字段定义、context、default_get 共同作用的结果。
很多“为什么没生效”就能立刻缩小范围。
为什么默认值经常像玄学
因为同一个字段的初始值,可能同时受到这些因素影响:
- 字段
default= - context 里的
default_xxx default_get()里动态计算- 当前入口带进来的
active_model / active_id / active_ids
如果你没意识到它们是叠加关系,而是只盯着某一个点看,就会觉得系统好像不稳定。
实际上,大多数时候不是 Odoo 抽风,而是你漏看了另一个来源。
字段 default= 是最基础的一层
这是最容易理解的默认值来源。
它表达的是:
- 如果没有别的更具体输入
- 这个字段通常默认给什么
它适合:
- 常量默认值
- 跟当前用户或环境轻度相关的默认值
- 比较稳定的初始行为
但它通常不适合非常依赖当前操作上下文的复杂默认逻辑。
context 里的 default_xxx 为什么这么常见
因为它很适合“从入口把意图带进来”。
比如你从某个按钮打开 wizard,可能就会带:
default_partner_iddefault_company_iddefault_move_type
这类默认值最像:
调用方在说:我希望打开表单时优先按这个来。
所以它特别适合:
- 按钮打开表单
- 不同入口打开同一模型
- wizard 预填当前记录相关值
default_get() 真正适合什么
default_get() 最适合处理:
- 多个字段需要联动决定默认值
- 默认值依赖当前上下文
- 需要按当前用户、公司、入口、选中记录综合判断
也就是说,它更像:
统一组装默认值的动态工厂。
如果只是给一个简单常量,没必要什么都塞进 default_get()。
但如果逻辑开始有条件分支,它就很有价值。
active_id / active_ids 为什么老出现
因为很多默认值都不是凭空来的,而是从“用户刚刚正在操作的那批记录”推出来的。
比如:
- 从销售单打开创建发票向导
- 从一批记录打开批量操作向导
- 从联系人页打开新建机会
这时 context 里往往会带:
active_modelactive_idactive_ids
它们本质上是在告诉你:
这次默认值逻辑,应该围绕哪批源记录展开。
为什么有时你明明写了 default,却还是不生效
常见原因通常就这几类:
1. 被 default_xxx 覆盖了
入口 context 优先表达了更具体意图。
2. 被 default_get() 改掉了
你后面动态组装时覆盖了前面值。
3. 当前视图或入口根本没带你以为的 context
你以为有 active_id,其实没有。
4. 字段本身在 create 过程中又被 onchange / 逻辑重算
默认值生效过,但后来被新逻辑改掉。
一个特别实用的排查顺序
如果默认值不对,建议按这个顺序查:
1. 字段定义里有没有 default=
先看静态基础值。
2. 打开入口有没有传 context
尤其检查 default_xxx。
3. default_get() 有没有覆盖
这是最常见的动态改写点。
4. active_model / active_id / active_ids 是否真存在
别按想象排查。
5. 后续 onchange 或 create 逻辑有没有再改值
很多人只查默认值阶段,忘了后面还有二次覆盖。
最稳的设计思路
我更推荐这样分工:
- 简单稳定默认值 → 放字段
default= - 入口相关默认值 → 放
context的default_xxx - 复杂动态拼装 → 放
default_get()
这样层次清楚,后面你自己回来看也不容易晕。
一句话记忆法
把它记成一句话:
字段 default 给基础值,context 给入口意图,default_get 负责动态组装,active_id/active_ids 提供当前操作上下文。
理解这一句,Odoo 默认值问题基本就不再玄学。
DISCUSSION
评论区