嵌入式动作

Odoo 嵌入式动作为什么只在特定记录上出现:active_id、domain、groups 和 user_id

嵌入式动作看起来像“只给某条记录用”的快捷入口。实际上,它会同时看 active_id、父记录、用户、分组和 domain。

Odoo 开发 框架
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 8 阅读

先说结论

ir.embedded.actions 不是“放在某个模型上的普通动作”。它更像是:

只有在当前上下文确实指向某条记录时,才可能出现的上下文动作。

所以你在列表里看不到它,并不奇怪。它本来就不是给“空上下文”准备的。

create() 做了什么

创建时,模型会做两件很实用的事:

  • 如果没传 name,就从 action_id 自动取名字
  • 如果同时传了 action_idpython_method,会根据值真假保留真正生效的一项

这说明嵌入式动作的设计目标不是“数据表存一条记录”,而是“让动作定义尽量可配置、可复用”。

可见性判断的核心:active_id

_compute_is_visible() 一开始就先看 active_id

如果上下文里没有 active_id,它直接判定不可见。

这一步很关键,因为后面的判断都建立在“当前有没有一个正在操作的目标记录”之上。

它到底在比对什么

可见性判断大致会同时看这些条件:

  • parent_res_model 是否匹配当前 active 模型
  • parent_res_id 是否为空,或等于当前 active_id
  • user_id 是否为空,或等于当前用户
  • groups_ids 是否允许当前用户
  • python_method 是否真的存在于目标模型上
  • domain 是否能让 active 记录通过过滤

也就是说,嵌入式动作并不是单一权限判断,而是上下文 + 记录归属 + 用户归属 + 规则过滤的组合。

为什么 domain 是针对 active record,而不是动作本身

很多人第一次看这里会误会:domain 好像是在过滤动作记录。

其实不是。

它是拿来过滤“当前激活的那条业务记录”的。

所以这段逻辑更像:

  • 先找到当前页面正在看的那条记录
  • 再判断这条记录是否满足嵌入式动作的可用条件

这也是为什么嵌入式动作特别适合“只对某些单据状态显示”的按钮或快捷入口。

为什么没有 active_id 时一律隐藏

这是设计边界,不是 bug。

嵌入式动作的前提就是“有一个明确的当前记录”。

没有 active_id 时,系统根本没法安全判断:

  • 这个动作应该挂到哪条记录
  • 是否属于当前用户
  • domain 是否应该通过

所以直接隐藏,比猜测更安全。

常见踩坑

1)父模型写错

parent_res_model 一旦不对,后面的判断全都对不上。

2)domain 写在了动作对象上,但实际想过滤别的记录

这里的 domain 只作用在当前 active 记录上。作用对象搞错,动作就永远不显示。

3)以为 user_idgroups_ids 任意一个满足就行

不是。它们是叠加关系,不是替代关系。

4)python_method 名字存在拼写错误

代码里会检查这个方法是否真的存在。名字写错,动作就直接变成不可见。

实战排查顺序

如果某个嵌入式动作不显示,我会先看:

  1. 当前页面有没有 active_id
  2. parent_res_modelparent_res_id 是否匹配
  3. user_id / groups_ids 是否挡住了当前用户
  4. domain 是否把 active 记录过滤掉了
  5. python_method 是否真正在模型上存在

一句话总结

嵌入式动作不是“挂上去就显示”,而是“当前记录、当前用户、当前规则都对上了才显示”。理解这一点,调试起来会快很多。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。