第8讲、Odoo 18 ORM 深度解析


Odoo 18 ORM 深度解析

Odoo 18 的 ORM(对象关系映射)是其最核心的部分之一,承担着模型定义、数据库操作、业务逻辑执行、权限控制、缓存机制等关键功能。Odoo ORM 通过 Python 类定义模型(Model),自动映射为 PostgreSQL 表,并借助丰富的装饰器、钩子和缓存机制实现功能增强。


🧠 一句话总结 Odoo ORM 原理

基于 Python 类、元编程和元模型注册机制,自动将类映射为 PostgreSQL 表,并提供统一的 CRUD、规则验证、上下文环境、事务控制与缓存优化的操作接口。


🧱 ORM 核心结构概览

odoo/
├── models/
│   ├── base.py           # Model 基类,注册/字段定义/元类处理
│   ├── fields.py         # 所有字段类型定义,如 Char、Many2one、One2many
│   ├── model.py          # 核心模型类 Model 的实现
│   ├── registry.py       # 注册表:管理所有模型类及数据库连接
│   ├── crud.py           # 实际执行 CRUD 操作的底层实现
│   ├── osv/
│   │   ├── orm.py        # 兼容老版本 osv API 的适配层
│   └── ...

🔄 ORM 生命周期与原理分析

1️⃣ 模型定义(Python class)

开发者通过如下方式定义模型:

class ResPartner(models.Model):
    _name = "res.partner"
    name = fields.Char()
    active = fields.Boolean(default=True)

背后过程:

  • 所有模型继承自 odoo.models.Model
  • 使用元类 MetaModel 拦截类定义,抽取 _name 和字段定义,并注册到 Registry
  • 字段通过 fields.* 类定义(如 Char, Boolean 等),每个字段在内存中表示为 Field 实例,带有 required, readonly, compute, inverse 等属性

2️⃣ 模型注册(MetaModel & Registry)

# odoo.models.base.MetaModel
class MetaModel(type):
    def __new__(mcs, name, bases, attrs):
        # 收集字段、约束等元信息
        ...
        # 注册模型到环境的注册表中
        cls = super().__new__(...)
        registry.register_model(cls)
# odoo.modules.registry.Registry
class Registry:
    def __init__(self, dbname):
        self.models = {}  # 存储所有模型
        ...

3️⃣ 数据库表创建(自动同步)

安装模块时,Odoo 根据模型结构调用 tools.convert.convert_xml_import() 自动创建数据库表结构。


4️⃣ CRUD 操作流程

📝 以 create() 为例:

partner = self.env['res.partner'].create({'name': 'Tom'})

实际流程:

  1. 入口方法为 Model.create()
    def create(self, vals):
        self._check_create_rights()
        self._validate_fields(vals)
        ...
        ids = self._create(vals)
        return self.browse(ids)
    
  2. 核心创建逻辑在 _create() 方法中,通过 cr.execute 直接写入数据库
  3. 自动计算字段、约束校验、触发 @api.onchange, @api.model_create_multi, @api.constrains 等钩子

🧩 CRUD 源码实现深度分析

Odoo ORM 的 CRUD(增删改查)操作不仅仅是 SQL 封装,还集成了权限校验、字段校验、钩子机制、批量优化、懒加载和缓存等多重机制。以 create() 为例,源码实现流程如下:

1. 统一入口:
所有模型都继承自 odoo.models.Model,开发者通过 self.env['model.name'].create(vals) 等方式调用 CRUD 方法。

2. create() 方法源码流程:

def create(self, vals):
    self._check_create_rights()
    self._validate_fields(vals)
    ...
    ids = self._create(vals)
    return self.browse(ids)
  • 权限校验_check_create_rights() 检查当前用户是否有创建权限
  • 字段校验_validate_fields(vals) 检查必填、只读、类型等约束
  • 核心写入_create(vals) 负责实际的数据库插入,底层通过 cr.execute 生成 SQL
  • 钩子机制:自动触发 @api.onchange, @api.model_create_multi, @api.constrains 等装饰器方法
  • 返回值:始终返回一个 recordset(即使只创建一条记录)

3. write()、unlink()、search() 实现:

  • write(vals):批量更新,先校验权限和字段,再通过 cr.execute 生成 UPDATE SQL,支持批量操作和自动触发相关钩子
  • unlink():删除操作,先校验权限和规则,再通过 cr.execute 生成 DELETE SQL,支持级联删除和钩子
  • search(domain):查询操作,domain 转为 SQL WHERE,支持复杂条件、分页、排序,返回 recordset

4. 底层实现与优化:

  • 底层 SQL 执行:所有 CRUD 最终都通过 self.env.cr.execute(sql, params) 与 PostgreSQL 交互
  • 批量优化:Odoo 会自动将多条操作合并为一条 SQL,减少 N+1 问题
  • 懒加载:recordset 只在访问字段时才真正查询数据库
  • 缓存机制:常用查询和字段值会被缓存,减少数据库压力

5. 权限与规则:

  • 每次 CRUD 前都会自动调用 _check_access_rights(模型级)、_check_record_rules(记录级)、_check_company(多公司)等方法,保证数据安全

6. 钩子与扩展:

  • 支持 @api.depends@api.onchange@api.constrains 等装饰器,开发者可自定义业务逻辑
  • 支持多种继承和 mixin,便于扩展和重载 CRUD 行为

7. 典型源码调用链(以 create 为例):

  1. self.env['res.partner'].create(vals)
  2. 进入 Model.create()(odoo/models/model.py)
  3. 权限校验、字段校验
  4. 调用 _create(),底层 cr.execute(INSERT ...)
  5. 触发相关钩子
  6. 返回 self.browse(ids),即 recordset

5️⃣ 多记录操作的支持:recordset 机制

recordset机制

Odoo 的 ORM 是 "记录集优先" 的,即使只有一条记录,API 也始终返回一个 recordset。

# 多记录统一调用写操作
partners = self.env['res.partner'].browse([1, 2, 3])
partners.write({'active': False})

Recordset 是一个可迭代对象,封装了 ID 列表与当前环境 (env),具备懒加载、批处理优化等特性。


6️⃣ 计算字段机制(@api.depends)

计算字段

total = fields.Float(compute='_compute_total')

@api.depends('amount', 'tax')
def _compute_total(self):
    for rec in self:
        rec.total = rec.amount + rec.tax

ORM 会自动根据依赖关系构建计算图,仅在相关字段变化时重新计算。


7️⃣ 缓存机制(ORM 缓存)

缓存机制

结合 odoo.tools.cache 模块的 @ormcache 实现自动缓存函数结果,如:

@ormcache('self.env.uid')
def get_partner_count(self):
    ...

字段值、recordset 本身也存在内存中做延迟加载(lazy load)。


8️⃣ 权限校验机制

权限校验

CRUD 操作前调用权限方法:

  • _check_access_rights
  • _check_record_rules
  • _check_company(多公司支持)

支持从 UI、RPC、XML-RPC 层自动传入用户上下文校验。


🧰 ORM 特性总结表

特性 描述 相关源码模块
模型注册 所有模型通过元类注册 base.py, registry.py
字段定义 字段类封装类型与属性 fields.py
多记录集支持 RecordSet 实现统一操作 model.py
动态计算 支持 @api.depends 自动刷新 api.py
数据校验 _check_*, @constrains 机制 model.py
缓存优化 @ormcache, record cache tools/cache.py
安全校验 权限 + 规则双重验证 access.py, rules.py
多语言支持 字段翻译机制 translate.py
上下文传递 self.env 携带上下文 api.py
多公司机制 company_dependent, check_company fields.py, model.py

🔄 ORM 实现图(简略)

┌───────────────┐
│ Python 模型类 │
└───────┬───────┘
        │
        ▼
   MetaModel
        │
        ▼
  注册表 Registry
        │
        ▼
  数据库表映射
        │
        ▼
  字段类型 (fields.X)
        │
        ▼
  CRUD 方法封装 (create/write/browse/search)
        │
        ▼
  权限 + 缓存 + 依赖 + API 修饰器
        │
        ▼
  PostgreSQL 数据库

✅ 总结一句话

Odoo ORM 是围绕"声明式模型 + 元编程注册 + 懒加载记录集 + 事务安全 + 上下文感知"的强大抽象层,它屏蔽了 SQL 细节,统一了数据与业务操作,极大提升了企业级开发的效率与安全性。


🧩 ORM 技术深度解读

1. 元编程与元类机制

Odoo ORM 的核心在于 Python 的元类(MetaModel),它不仅负责模型注册,还实现了字段收集、继承链处理、自动生成 SQL 映射等。

  • 字段收集与继承:MetaModel 会递归父类,合并所有字段定义,支持多重继承和字段重载。
  • 自动生成表结构:通过分析 _name、字段类型、约束等,自动生成 PostgreSQL 的表结构和索引。
  • 模型生命周期钩子:如 __init__, __new__, __setup__,用于模型初始化和扩展。

2. 字段类型与高级特性

  • 关系字段:如 Many2one, One2many, Many2many,自动处理外键、联表、级联删除等。
  • 动态属性:如 compute, inverse, search, related,实现自动计算、反向写入、自定义搜索等。
  • 字段扩展:支持 selection, context_dependent, company_dependent 等高级特性。

3. 环境(env)与上下文机制

  • self.env 是 Odoo ORM 的"上下文载体",包含当前用户、公司、语言、事务等信息。
  • 支持多数据库(多租户)、多公司、动态上下文切换,保证数据隔离与权限安全。

4. 事务与一致性保障

  • 所有操作都在 PostgreSQL 事务中执行,支持自动回滚、嵌套事务(savepoint)、乐观锁等。
  • 支持 @api.autovacuum, @api.model_cr 等钩子,自动维护数据一致性和表结构升级。

5. 性能优化机制

  • 延迟加载(Lazy Load):Recordset 只在访问字段时才查询数据库,避免不必要的 SQL。
  • 批量操作优化:如 write, unlink 支持批量 SQL,减少循环和 N+1 查询。
  • 缓存机制@ormcache 支持参数化缓存,字段值缓存,减少重复计算和数据库访问。

6. 安全与权限体系

  • 多层权限校验:模型级(access rights)、记录级(record rules)、字段级(field access)、公司级(multi-company)。
  • 上下文感知:权限校验自动感知当前用户、公司、上下文,支持自定义规则和动态调整。

7. 扩展性与自定义能力

  • 支持通过继承(_inherit)、mixin、装饰器(@api.model, @api.depends, @api.constrains)等方式灵活扩展模型和业务逻辑。
  • 支持模块化开发,模型和字段可被多个模块动态扩展和重载。

8. 与外部系统集成

  • ORM 屏蔽了 SQL 细节,支持通过 RPC、XML-RPC、JSON-RPC、REST API 等多种方式与外部系统交互。
  • 支持自动序列化、反序列化、权限校验和上下文传递。

9. 典型源码流程图

flowchart TD A -->Python模型类MyModel(models.Model) --> B[MetaModel元类字段/元信息收集] B --> C[注册表 Registry模型注册/管理] C --> D[数据库表映射自动建表/同步] D --> E[CRUD方法封装create/write/search/unlink] E --> F[权限校验_check_access_rights/_check_record_rules] E --> G[缓存机制 @ormcache/懒加载] E --> H[依赖与钩子 @api.depends/@api.onchange] F --> I[PostgreSQL数据库] G --> I H --> I

10. 常见开发/调试技巧

  • 使用 self.env.cr 直接执行 SQL 以优化特殊场景。
  • 利用 @api.model_create_multi 优化批量创建性能。
  • 善用 @api.depends 精确声明依赖,避免不必要的计算。
  • 通过 sudo()with_context()with_company() 灵活切换权限和上下文。

posted @ 2025-05-30 11:42  何双新  阅读(294)  评论(0)    收藏  举报