odoo-orm-expert
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOdoo ORM Expert
Odoo ORM 专家
Overview
概述
This skill teaches you Odoo's Object Relational Mapper (ORM) in depth. It covers reading/writing records, building domain filters, working with relational fields, and avoiding common performance pitfalls like N+1 queries.
本技能将深入讲解Odoo的对象关系映射(ORM)。内容涵盖记录的读写、域过滤器的构建、关联字段的使用,以及如何避免N+1查询等常见的性能陷阱。
When to Use This Skill
何时使用本技能
- Writing ,
search(),browse(),create(), orwrite()calls.unlink() - Building complex domain filters for views or server actions.
- Implementing computed, stored, and related fields.
- Debugging slow queries or optimizing bulk operations.
- 编写、
search()、browse()、create()或write()调用时。unlink() - 为视图或服务器操作构建复杂的域过滤器时。
- 实现计算字段、存储字段和关联字段时。
- 调试慢查询或优化批量操作时。
How It Works
工作方式
- Activate: Mention and describe what data operation you need.
@odoo-orm-expert - Get Code: Receive correct, idiomatic Odoo ORM code with explanations.
- Optimize: Ask for performance review on existing ORM code.
- 激活:提及并描述你需要的数据操作。
@odoo-orm-expert - 获取代码:获取正确、符合Odoo风格的ORM代码及解释。
- 优化:请求对现有ORM代码进行性能审查。
Examples
示例
Example 1: Search with Domain Filters
示例1:使用域过滤器进行搜索
python
undefinedpython
undefinedFind all confirmed sale orders for a specific customer, created this year
查找特定客户今年创建的所有已确认销售订单
import datetime
start_of_year = datetime.date.today().replace(month=1, day=1).strftime('%Y-%m-%d')
orders = self.env['sale.order'].search([
('partner_id', '=', partner_id),
('state', '=', 'sale'),
('date_order', '>=', start_of_year),
], order='date_order desc', limit=50)
import datetime
start_of_year = datetime.date.today().replace(month=1, day=1).strftime('%Y-%m-%d')
orders = self.env['sale.order'].search([
('partner_id', '=', partner_id),
('state', '=', 'sale'),
('date_order', '>=', start_of_year),
], order='date_order desc', limit=50)
Note: pass dates as 'YYYY-MM-DD' strings in domains,
注意:在域中需将日期以'YYYY-MM-DD'字符串形式传递,
NOT as fields.Date objects — the ORM serializes them correctly.
而非fields.Date对象——ORM会正确序列化它们。
undefinedundefinedExample 2: Computed Field
示例2:计算字段
python
total_order_count = fields.Integer(
string='Total Orders',
compute='_compute_total_order_count',
store=True
)
@api.depends('sale_order_ids')
def _compute_total_order_count(self):
for record in self:
record.total_order_count = len(record.sale_order_ids)python
total_order_count = fields.Integer(
string='Total Orders',
compute='_compute_total_order_count',
store=True
)
@api.depends('sale_order_ids')
def _compute_total_order_count(self):
for record in self:
record.total_order_count = len(record.sale_order_ids)Example 3: Safe Bulk Write (avoid N+1)
示例3:安全的批量写入(避免N+1查询)
python
undefinedpython
undefined✅ GOOD: One query for all records
✅ 推荐:一次查询处理所有记录
partners = self.env['res.partner'].search([('country_id', '=', False)])
partners.write({'country_id': self.env.ref('base.us').id})
partners = self.env['res.partner'].search([('country_id', '=', False)])
partners.write({'country_id': self.env.ref('base.us').id})
❌ BAD: Triggers a separate query per record
❌ 不推荐:每条记录触发一次单独查询
for partner in partners:
partner.country_id = self.env.ref('base.us').id
undefinedfor partner in partners:
partner.country_id = self.env.ref('base.us').id
undefinedBest Practices
最佳实践
- ✅ Do: Use ,
mapped(), andfiltered()on recordsets instead of Python loops.sorted() - ✅ Do: Use sparingly and only when you understand the security implications.
sudo() - ✅ Do: Prefer over
search_count()when you only need a count.len(search(...)) - ✅ Do: Use to pass context values cleanly rather than modifying
with_context(...)directly.self.env.context - ❌ Don't: Call inside a loop — this is the #1 Odoo performance killer.
search() - ❌ Don't: Use raw SQL unless absolutely necessary; use ORM for all standard operations.
- ❌ Don't: Pass Python /
datetimeobjects directly into domain tuples — always stringify them asdate.'YYYY-MM-DD'
- ✅ 建议:在记录集上使用、
mapped()和filtered(),而非Python循环。sorted() - ✅ 建议:谨慎使用,且仅在了解其安全影响时使用。
sudo() - ✅ 建议:当你只需要计数时,优先使用而非
search_count()。len(search(...)) - ✅ 建议:使用干净地传递上下文值,而非直接修改
with_context(...)。self.env.context - ❌ 禁止:在循环内调用——这是Odoo性能问题的头号元凶。
search() - ❌ 禁止:除非绝对必要,否则不要使用原始SQL;所有标准操作都应使用ORM。
- ❌ 禁止:直接将Python/
datetime对象传入域元组——始终将其格式化为date字符串。'YYYY-MM-DD'
Limitations
局限性
- Does not cover raw SQL patterns in depth — use the Odoo performance tuner skill for SQL-level optimization.
cr.execute() - Stored computed fields can cause significant write overhead at scale; this skill does not cover partitioning strategies.
- Does not cover transient models () or wizard patterns.
models.TransientModel - ORM behavior can differ slightly between Odoo SaaS and On-Premise due to config overrides.
- 不深入讲解**原始SQL**模式——如需SQL级别的优化,请使用Odoo性能调优技能。
cr.execute() - 存储计算字段在大规模场景下会导致显著的写入开销;本技能不涉及分区策略。
- 不涉及临时模型()或向导模式。
models.TransientModel - 由于配置覆盖,Odoo SaaS与本地部署版本的ORM行为可能略有不同。