归档过滤

Odoo 的 active_test 到底在偷偷影响什么:为什么归档记录像“凭空消失”

你明明没写 `('active', '=', True)`,搜索结果却默认把归档记录排除了;你明明知道有那条数据,下拉框却像没看见它。很多这类问题,根子都在 active_test 这层隐式过滤上。

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

很多“查不到数据”问题,其实不是权限问题

在 Odoo 里,很多人一碰到这几种现象,就会立刻怀疑权限或记录规则:

  • 搜索查不到已知存在的记录
  • Many2one 下拉框里没有那条归档对象
  • One2many 看起来比数据库里少
  • 切个上下文后,同一个关联字段突然“多出几条记录”

但源码里有一层更隐蔽、也更常见的原因:active_test

它的厉害之处就在于:

  • 你经常没有显式写它
  • 但它却默认在生效

所以很多人会觉得它像“系统偷偷动了手脚”。

其实不是偷偷,是框架故意替你做了默认过滤。


_search() 会自动补一条 active = True

odoo/orm/models.py_search() 里,逻辑非常清楚。

只要同时满足这些条件:

  • 模型存在 _active_name
  • active_test=True
  • env.context.get('active_test', True) 也是真
  • 你的 domain 里又没有显式碰到 active 字段条件

框架就会自动把 domain 补成:

  • active = True

这就是为什么你明明只写了:

self.env['res.partner'].search([('name', 'ilike', 'Azure')])

结果却默认查不到归档 partner。

不是因为 Odoo 觉得你不配看,而是因为:

在没有特别声明的情况下,框架把“活跃记录”视为默认工作集。


它为什么要这样设计

因为归档语义的目标,本来就不是“把记录删掉”,而是:

  • 数据继续留着
  • 但默认操作面尽量别被历史记录污染

如果没有 active_test 这层默认过滤,很多日常界面和业务搜索都会被归档对象挤满:

  • 客户选择器
  • 产品选择器
  • 员工关联
  • 历史配置引用

于是用户会觉得系统很乱。

所以 Odoo 的默认立场不是“展示所有记录,再让用户自己分辨”,而是:

默认只给你当前还活跃、还值得参与日常流程的记录。


为什么它最容易在关联字段里制造错觉

因为你不一定是自己手写了 search()

很多时候,过滤发生在更深一层:

  • Many2one 候选读取
  • One2many 反向读取
  • 字段定义自带 context
  • 某些关系字段在访问时自动沿用上下文

/home/ubuntu/odoo-temp 的测试代码里,你能看到很多显式的:

context={'active_test': False}

这不是装饰品,而是在告诉框架:

  • 这条关系读取时,不要再默认屏蔽归档记录

也正因为如此,两个看起来差不多的字段,可能只因为其中一个字段定义里加了:

context={'active_test': False}

最终界面体验就完全不同。


One2many 为什么经常最让人迷惑

测试里还专门覆盖了 test_12_active_test_one2many() 这类场景。

这说明 Odoo 官方自己也知道:

  • One2many 读取时的 active_test
  • 创建/写入时的上下文
  • 你后续重新访问字段时的上下文

这三件事很容易让开发者误解。

一个很典型的错觉是:

  • 我明明往子表里写进去了记录
  • 为什么父表重新打开后只看到一部分

答案往往不是“没写进去”,而是:

  • 写进去了
  • 但其中一部分子记录已经 active=False
  • 你当前访问 One2many 时又处在默认 active_test=True
  • 所以它们被隐式藏起来了

这就是“数据库有,界面像没有”的标准来源之一。


为什么显式写了 active 条件时,系统反而不再帮你补

_search() 那段逻辑还有个关键保护:

  • 只有当 domain 里没有显式涉及 active 字段时,才自动追加 active=True

这意味着只要你自己写了:

  • ('active', '=', False)
  • ('active', 'in', [True, False])
  • 或别的 active 条件

框架就会认为:

  • 你已经明确表达了意图
  • 不再替你做默认判断

这其实是个很合理的边界:

  • 没说时,系统帮你默认过滤
  • 说了时,系统尊重你的口径

最容易误判的 4 个地方

误判 1:查不到记录就是权限不够

很多时候不是 ACL,也不是记录规则,只是归档过滤还开着。

误判 2:归档记录只影响列表页,不影响关联字段

不对。Many2one、One2many、Many2many 的读取体验都可能受上下文影响。

它经常还会影响你后续访问关系字段时的可见范围,因为 recordset/field 读取本身会携带上下文。

误判 4:写入归档记录失败,说明系统不支持归档对象参与业务

有时候不是“不能参与”,而是“默认不显示”。这两个结论差很多。


实战排查顺序

以后你再遇到“数据像消失了一样”的问题,我建议按这个顺序排:

  1. 目标模型有没有 active 字段或 _active_name
  2. 当前 env.contextactive_test 是真还是假
  3. domain 里有没有已经显式写 active 条件
  4. 关系字段定义里有没有 context={'active_test': False}
  5. 你是在查主模型,还是在读取某个关联字段

这五步一过,很多玄学问题会瞬间变成普通问题。


最后一句话

active_test 最值得记住的,不是“它能关掉归档过滤”,而是:

只要你没明确说别的,Odoo 默认就把“只看 active=True”当成搜索基线。

所以归档记录不是没了,很多时候只是被默认工作视角藏起来了而已。

DISCUSSION

评论区

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