很多“查不到数据”问题,其实不是权限问题
在 Odoo 里,很多人一碰到这几种现象,就会立刻怀疑权限或记录规则:
- 搜索查不到已知存在的记录
- Many2one 下拉框里没有那条归档对象
- One2many 看起来比数据库里少
- 切个上下文后,同一个关联字段突然“多出几条记录”
但源码里有一层更隐蔽、也更常见的原因:active_test。
它的厉害之处就在于:
- 你经常没有显式写它
- 但它却默认在生效
所以很多人会觉得它像“系统偷偷动了手脚”。
其实不是偷偷,是框架故意替你做了默认过滤。
_search() 会自动补一条 active = True
在 odoo/orm/models.py 的 _search() 里,逻辑非常清楚。
只要同时满足这些条件:
- 模型存在
_active_name active_test=Trueenv.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 的读取体验都可能受上下文影响。
误判 3:with_context(active_test=False) 只影响当前 search 调用
它经常还会影响你后续访问关系字段时的可见范围,因为 recordset/field 读取本身会携带上下文。
误判 4:写入归档记录失败,说明系统不支持归档对象参与业务
有时候不是“不能参与”,而是“默认不显示”。这两个结论差很多。
实战排查顺序
以后你再遇到“数据像消失了一样”的问题,我建议按这个顺序排:
- 目标模型有没有
active字段或_active_name - 当前
env.context里active_test是真还是假 - domain 里有没有已经显式写 active 条件
- 关系字段定义里有没有
context={'active_test': False} - 你是在查主模型,还是在读取某个关联字段
这五步一过,很多玄学问题会瞬间变成普通问题。
最后一句话
active_test 最值得记住的,不是“它能关掉归档过滤”,而是:
只要你没明确说别的,Odoo 默认就把“只看 active=True”当成搜索基线。
所以归档记录不是没了,很多时候只是被默认工作视角藏起来了而已。
DISCUSSION
评论区