第四章 ORM 核心操作
篇别:第一篇 基础知识
本章学习目标
- 熟练使用 CRUD、search、browse 与记录集运算。
- 掌握 env、sudo、context 的正确用法与风险。
- 了解 Odoo 19 废弃属性 与
search_fetch/_search_display_name等新实践。
4.1 CRUD 操作
4.1.1 知识要点
create:可传字典列表批量创建。write:批量更新;避免循环内逐条 write。unlink:注意ondelete、mail 线程、约束。copy:default覆盖字段。
4.1.2 案例
案例 A:批量创建
self.env['library.book'].create([
{'name': 'Odoo 开发', 'isbn': '001'},
{'name': 'Python 基础', 'isbn': '002'},
])
案例 B:安全删除前检查
def unlink(self):
if any(r.state == 'done' for r in self):
raise UserError('已完成记录不可删除')
return super().unlink()
4.1.3 截图占位

4.1.4 本节练习
- 简答:为何推荐
create([{...},{...}])而非两次create({...})? - 实操:写方法将所选记录
state批量改为done(单条 SQL 可用write一次完成)。
参考答案提示:1. 减少往返与事务开销。
4.2 查询操作
4.2.1 知识要点
search、read、browse、default_get、fields_get;显示名相关向 _search_display_name 演进。
4.2.2 案例
Book = self.env['library.book']
books = Book.search([('name', 'ilike', 'odoo')], limit=10, order='name')
data = books.read(['name', 'isbn'])
4.2.3 截图占位

4.2.4 本节练习
- 填空:
browse返回的是 __,即使 id 不存在也可能不立即报错(访问字段时校验)。 - 实操:用
search_read取前 20 本书的name、isbn。
参考答案提示:1. 记录集。
4.3 记录集(Recordset)
4.3.1 知识要点
记录集 不可变;filtered、mapped、sorted、grouped(版本 API 以文档为准)。
4.3.2 案例
draft = orders.filtered(lambda r: r.state == 'draft')
names = partners.mapped('name')
4.3.3 截图占位

4.3.4 本节练习
- 简答:
mapped与 Python 列表推导在 ORM 缓存上的差异概要?
4.4 环境(Environment)
4.4.1 知识要点
env.cr、env.user、env.company、env.context;sudo() 绕过权限,慎用;with_company 多公司。
4.4.2 案例
# 仅演示:在可控边界内为报表汇总切换公司
lines.with_company(company).read(['balance'])
4.4.3 截图占位

4.4.4 本节练习
- 判断:
sudo()后无需再检查业务规则。( ) - 实操:用普通用户与超级用户分别
search同一模型,对比条数差异并解释记录规则影响。
参考答案提示:1. 错。
4.5 高效查询(补充)
4.5.1 知识要点
search_fetch、fetch:减少 SQL 次数,缓解 N+1。
4.5.2 案例
records = Model.search_fetch(domain, ['name', 'partner_id'])
具体签名以 19.0 文档为准。
4.5.3 截图占位

4.5.4 本节练习
- 实操:找一段循环内访问
line.product_id.name的代码,改为预取优化。
4.6 Odoo 19 废弃项(新增)
4.6.1 知识要点
弃用 record._cr、_context、_uid,统一 record.env.cr 等。
4.6.2 案例
# 旧(避免)
# cr = self._cr
# 新
cr = self.env.cr
4.6.3 截图占位

4.6.4 本节练习
- 实操:在自定义模块中全局搜索
_cr并改为env.cr。
4.7 方法装饰器(新增)
4.7.1 知识要点
@api.model、@api.model_create_multi、@api.depends、@api.onchange、@api.constrains、@api.private(RPC 可见性策略以文档为准)。
4.7.2 案例
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals.setdefault('name', '未命名')
return super().create(vals_list)
4.7.3 截图占位

4.7.4 本节练习
- 简答:
@api.model_create_multi与重写create时忘记调用super的风险?
4.8 _search_display_name(新增)
4.8.1 知识要点
自定义「按显示名搜索」时实现 _search_display_name(签名以官方为准),避免低效 name_search 扩展遗留。
4.8.2 案例
伪代码:在模型上重写 _search_display_name,对 code、name 做 ilike 组合 domain。
4.8.3 截图占位

4.8.4 本节练习
- 拓展:阅读官方示例,实现按 ISBN 搜书。
本章综合练习
- 实现:
merge_partners方法,合并重复res.partner并重写子表外键(慎用,先备份)。 - 论述:
sudo与with_user的区别与审计建议。
本章对应白皮书目录:第四章 ORM 核心操作。