归档过滤

Odoo 的 active_test:为什么归档后数据突然“消失”了

从 `_search(..., active_test=True)` 看懂默认过滤、上下文开关和“查得到但看不到”的真正原因。

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

先说结论

很多人第一次碰到 Odoo 归档时,都会问同一个问题:

“我明明没有删数据,为什么搜索结果里不见了?”

答案通常不是数据消失了,而是 active_test 把它过滤掉了

在 Odoo 里,归档不是删除。它只是把记录的 active 标志置为 False。默认搜索时,ORM 会把这类记录挡在结果外面。


源码里,默认过滤是怎么加上的

odoo/orm/models.py_search() 里,Odoo 会先检查:

  • 当前模型有没有 active 字段
  • active_test 参数是不是开启
  • context 里是不是也允许 active_test
  • 你的 domain 里有没有已经显式写了 active

如果都满足,ORM 就会自动补上一条条件:

('active', '=', True)

这意味着你平时写的:

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

实际上往往会变成“只搜 active 的 Acme”。


为什么这条默认条件很容易让人误判

因为它不是显式写在你的 domain 里,而是 ORM 在内部补上的。

所以你会感觉:

  • 菜单里明明有这个记录
  • 数据库里明明查得到
  • 但是 search() 返回空

这通常就是 active_test 在起作用。

特别是在这些场景里最常见:

  • 客户、产品、供应商、联系人被归档
  • Many2one 下拉框里找不到旧数据
  • 自定义报表少了“历史对象”

什么时候可以关闭它

如果你确实要把归档记录也算进去,可以显式关闭:

records = self.with_context(active_test=False).search(domain)

或者在更底层的调用里,直接把 active_test=False 传进去。

关闭后,ORM 不会自动帮你补 active=True,归档记录就会重新进入搜索范围。


一个容易忽略的细节:显式 domain 会改变默认行为

如果你的 domain 里已经写了 active 条件,ORM 就不会再重复加一层默认过滤。

这能避免出现“双重筛选”。

所以像下面这样的查询:

[('active', 'in', [True, False])]

就是在告诉 ORM:我自己已经决定要不要包含归档记录了。


search 看不到,不代表 browse 不存在

这是很多人会混淆的点。

  • search() 受 domain、权限和 active_test 影响
  • browse(ids) 只是按 id 取记录集,不等于马上做同样的搜索过滤

所以排障时,不要把“搜索不到”直接等同于“记录没了”。先看它是不是被归档了,再看 context 里有没有 active_test=False


为什么这条规则对系统性能也有帮助

从设计上看,归档记录默认不参与搜索,能减少很多无意义的结果集。

尤其是大表里,历史记录往往比有效记录多。默认过滤能让:

  • 下拉框更干净
  • 搜索更快
  • 业务界面更聚焦当前可用数据

这也是为什么 Odoo 把 active 设计成默认行为,而不是让每个调用者自己手写过滤。


实战里怎么排查“记录消失”

可以按这个顺序:

  1. 看记录是否只是归档了
  2. 看当前代码是否用了 with_context(active_test=False)
  3. 看 domain 里有没有显式过滤 active
  4. 看 Many2one / 搜索面板是不是默认只展示 active 数据

很多问题其实不是权限,也不是 SQL,而只是默认过滤。


结尾

你可以把 active_test 记成一句话:

归档不是删除,active_test 只是默认不让它出现在搜索结果里。

理解这一点,很多“数据丢了”的误会就会立刻消失。

DISCUSSION

评论区

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