Odoo 开发里,context 是那种“人人都知道重要,但也人人都容易越用越乱”的东西。
尤其是这些写法:
default_partner_idsearch_default_my_recordsgroup_bydefault_typeactive_id
很多时候项目里会逐渐变成一种模糊经验:
反正 context 很神,想让界面默认成什么样,就先往里塞一把试试。
但从 /home/ubuntu/odoo-temp/odoo/addons/base/models/ir_ui_view.py 和整个 Web/ORM 交互的语义来看,context 不是“万能口袋”,而是一套前后端之间约定好的 UI 合约。不同 key,其实是在对不同层说话。
一、先把问题分清:不是所有 context key 都在做同一件事
开发里最常混的三类 key 是:
1)default_...
这是在对“新建记录的默认值”说话。
例如:
{'default_partner_id': partner.id}
它的语义是:当用户打开创建表单时,如果新记录里有 partner_id 这个字段,就把默认值设成这里给的内容。
2)search_default_...
这是在对“搜索视图里的默认筛选器”说话。
例如:
{'search_default_my_orders': 1}
它不是给模型字段赋值,也不是 domain 本身,而是在告诉搜索面板:
- 如果存在名为
my_orders的 filter - 默认帮我勾上它
3)group_by
这是在对“当前列表/报表/聚合界面默认按什么分组”说话。
它和 default_ 的语义完全不是一类。
如果把这三类混成“都是 context 里某个参数”,后面很容易越改越乱。
二、default_ 的核心边界:它影响新建默认值,不等于落库值
很多人会误以为:
context = {'default_xxx': value}
等于“这个字段一定会是这个值”。
其实不是。
更准确地说,它影响的是:
- 新建表单初始化时
default_get()/ 默认值链路- 记录刚开始长出来时的初始状态
后面用户仍然可以:
- 手工改掉
- 被 onchange 改掉
- 被 create/write 逻辑重算
所以 default_ 的边界是“初始建议值”,不是“最终落库强制值”。
这也是为什么 context 默认值经常和 default_get()、onchange 一起看,单看一层很容易误判。
三、search_default_ 的核心边界:它激活的是搜索项,不是直接拼 domain
这是另一类特别容易被误解的键。
很多人看到:
{'search_default_customer': 1}
会下意识理解成“给 domain 加 customer 过滤”。
但它真正的语义更像:
- 搜索视图里如果有一个对应 filter
- 默认勾选它
- 再由这个 filter 自己定义 domain / context / group 展现
所以如果你塞了一个 search_default_xxx 却没效果,先别急着怀疑 action context 丢了,更该先检查:
- 搜索视图里到底有没有对应名字的 filter
- 这个 filter 定义的到底是什么
- 当前 action / view 是否真的用了那张 search view
也就是说,search_default_ 是对搜索 UI 组件发信号,不是 ORM domain 的直接替身。
四、group_by 真的是被显式校验的,不是你想写什么都行
这一点在 ir_ui_view.py 里非常清楚。
Odoo 在校验 XML 视图节点的 context 属性时,会专门检查其中的 group_by:
- 它必须是字符串
- 字符串里引用的字段必须真实存在于模型上
源码甚至直接在视图校验阶段抛出类似:
"group_by" value must be a stringUnknown field ... in "group_by" value
这说明 group_by 不是“前端自己猜着用”的自由文本,而是一个被框架明确验证的上下文协议。
这也解释了为什么有些 XML 明明能安装别的 context key,却会在 group_by 上直接报视图错误:因为它是有结构约束的。
五、为什么说这些 key 是“在跟不同对象说话”
这是理解 context 最有帮助的角度。
default_...
在跟:
- 默认值计算链
- 新建表单初始化
default_get()
说话。
search_default_...
在跟:
- 搜索视图
- 筛选器开关
- 搜索 UI 状态
说话。
group_by
在跟:
- 当前视图的默认分组
- 分组字段校验规则
- Web 客户端的 group 展现逻辑
说话。
把它们统称为“都是 context 参数”当然没错,但这会掩盖它们其实面向不同消费方。
六、最常见的项目级误用
误用 1:想强制字段值,却只塞 default_
如果你的需求是“这个字段最终不能被改”,那你靠 default_ 往往不够。它只是初始值入口。
误用 2:以为 search_default_ 不生效是模型问题
很多时候根因根本不在模型,而在:
- filter 名字不匹配
- search view 没挂上
- 当前 action 用的不是你以为那张搜索视图
误用 3:把 group_by 当成任意表达式
源码已经明确告诉你,它不是随便写的;字段名不对、格式不对,视图层就会拦下来。
七、一个更稳定的排查顺序
以后碰到“为什么 context 没按我想的生效”,建议先问:
第一步:这个 key 想影响的是哪一层?
- 默认值
- 搜索 UI
- 分组表现
- 还是别的 ORM 行为
第二步:这一层是否真的消费这个 key?
比如:
search_default_foo有没有对应 filtergroup_by的字段是不是存在default_bar对应字段在创建链上会不会马上被 onchange 改掉
第三步:是否把“初始状态”误认为“最终结果”
很多 context bug,本质上不是 key 失效,而是后续链路又把初始值改掉了。
结语
Odoo 里的 context 强大,但它不是“往里塞参数,系统自然会懂”的黑盒。
更准确的理解应该是:
default_...负责新建默认值search_default_...负责默认激活搜索筛选器group_by负责默认分组,而且会被视图层严格校验
所以真正该掌握的不是“context 很神”,而是:
每一种 context key,都有它明确的消费方和边界;一旦把消费方搞错,行为就会看起来像失灵。
DISCUSSION
评论区