视图继承

Odoo 视图继承不是“把 XML 复制一份”:XPath、position 和 primary/extension 讲透

看懂 ir.ui.view 如何把继承链拼成最终 arch,为什么 XPath 找不到、position 失效,往往不是 Odoo 随机坏了。

Odoo 开发 前端
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 16 阅读

先把问题说透

Odoo 的视图继承不是“改一份 XML 然后覆盖原文件”。 它更像是在一棵树上打补丁:先找到父视图,再把一组继承规则按顺序贴上去,最后生成用户真正看到的 arch。

这也是为什么开发者最常遇到的报错,不是“XML 格式错了”,而是:

  • XPath 找到了错误的节点
  • position="replace" 把结构换没了
  • 继承链里有 primary / extension 的顺序问题
  • 你以为改到了当前视图,其实改的是更上层的父视图

先理解这一点,后面的很多坑都会变得很直观。

primary 和 extension 不是装饰词,而是执行顺序

ir.ui.view 里,mode='extension' 表示“给父视图继续打补丁”;mode='primary' 表示“先把某个基底视图完全解析出来,再把自己当成新的主视图”。

_combine() 的核心思路是深度优先遍历:

  1. 先取当前主视图的 arch
  2. 再按继承树把它的子视图排进队列
  3. 扩展视图优先贴补丁
  4. 碰到新的 primary 时,把它当作新主干继续展开

所以,继承顺序不是“谁先写谁先生效”这么简单,而是“树上哪个节点先被展开,哪个补丁先被贴上”。

这也解释了一个很常见的现象:

同样的 XPath,在一个模块里能命中,在另一个模块里却失效。

不是 Odoo 随机,而是你命中的节点已经被更上游的视图改掉了。

apply_inheritance_specs 真正做了什么

视图的继承规则最终会交给 odoo.tools.template_inheritance.apply_inheritance_specs()。 这一层做的事情很朴素:

  • 先定位目标节点
  • 再按 position 执行修改
  • 最后把结果写回合并后的 arch

常见 position 的含义可以直接记成一句话:

  • before / after:插到目标节点前后
  • inside:插到目标节点内部
  • replace:整块替换
  • attributes:只改属性
  • move:把已有节点挪位置

这里最容易误解的是 attributes。 它不是“改了属性就不影响结构”,而是“只改属性值,但仍然可能影响后续校验和渲染”。

另一个关键点是 pre_locatelocate_node:它们负责在真正应用补丁前找到匹配节点。XPath 不是魔法,它只是一个定位规则;节点被其他继承层改掉后,定位就可能失败。

为什么调试时会看到 data-oe-xpath

Odoo 在继承和品牌标记相关上下文里,会给节点打上 data-oe-iddata-oe-modeldata-oe-fielddata-oe-xpath 等标记。

这不是为了美观,而是为了调试:

  • 你可以知道当前节点来自哪个 view
  • 可以知道它在合并后树里的路径
  • 还可以定位到底是哪个继承层改坏了结构

如果启用了 partial validation,代码还会根据 validate_view_ids 给节点打 __validate__ 标记。它的作用是让校验只盯住真正受影响的局部,而不是整棵树全扫。

新手最容易踩的 4 个坑

  1. XPath 目标太脆弱 用文本、位置序号或太宽泛的条件去找节点,升级后很容易炸。

  2. 把 extension 当成 primary 你以为自己定义的是主视图,实际上只是往别人的树上插了一段。

  3. 忽略上游模块的继承层 只看当前文件,不看父视图和兄弟视图,最后只能靠猜。

  4. 只会 replace,不会 attributes 很多需求其实只要改个 readonlyinvisiblerequired,没必要整块替换。

一页实战检查清单

当视图补丁没生效时,按这个顺序查:

  • 先确认 inherit_id 指向谁
  • 再确认当前视图是 primary 还是 extension
  • 看 XPath 能不能命中合并前的节点
  • 看上游模块有没有先改过同一块
  • 最后再看 group_ids、active 和上下文是否把视图挡掉了

只要把“合并树”和“定位规则”分开看,Odoo 视图继承就不会再显得神秘。

DISCUSSION

评论区

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