第8讲、Odoo 18 ORM 深度解析

article/2025/7/5 0:39:46

文章目录

    • @[toc]
  • Odoo 18 ORM 深度解析
    • 🧠 一句话总结 Odoo ORM 原理
    • 🧱 ORM 核心结构概览
    • 🔄 ORM 生命周期与原理分析
      • 1️⃣ 模型定义(Python class)
      • 2️⃣ 模型注册(MetaModel & Registry)
      • 3️⃣ 数据库表创建(自动同步)
      • 4️⃣ CRUD 操作流程
        • 📝 以 `create()` 为例:
        • 🧩 CRUD 源码实现深度分析
      • 5️⃣ 多记录操作的支持:`recordset` 机制
      • 6️⃣ 计算字段机制(@api.depends)
      • 7️⃣ 缓存机制(ORM 缓存)
      • 8️⃣ 权限校验机制
    • 🧰 ORM 特性总结表
    • 🔄 ORM 实现图(简略)
    • ✅ 总结一句话
    • 🧩 ORM 技术深度解读
      • 1. 元编程与元类机制
      • 2. 字段类型与高级特性
      • 3. 环境(env)与上下文机制
      • 4. 事务与一致性保障
      • 5. 性能优化机制
      • 6. 安全与权限体系
      • 7. 扩展性与自定义能力
      • 8. 与外部系统集成
      • 9. 典型源码流程图
      • 10. 常见开发/调试技巧

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 机制

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 cachetools/cache.py
安全校验权限 + 规则双重验证access.py, rules.py
多语言支持字段翻译机制translate.py
上下文传递self.env 携带上下文api.py
多公司机制company_dependent, check_companyfields.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 TDA -->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 --> IH --> I

在这里插入图片描述

10. 常见开发/调试技巧

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


http://www.hkcw.cn/article/vaNuYjmDBN.shtml

相关文章

网络编程套接字

目录 1.Socket套接字 1.1TCP和UDP的区别 2.UDP api的使用 2.1DatagramSocket 2.2DatagramPacket 3.UDP数据报套接字编程 3.1UdpEchoServer服务器 3.2UdpEchoClient客户端 3.3客户端和服务器相互配合的完整流程 4.TCP api的使用 4.1ServerSocket 4.2Socket 4.TCP数据…

秋招Day12 - 计算机网络 - TCP

详细说一下TCP的三次握手机制 TCP的三次握手机制是为了在两个主机之间建立可靠的连接,这个机制确保两端的通信是同步的,并且在开始传输数据前,双方都做好了要通信的准备。 说说SYN的概念? SYN 是 TCP 协议中用来建立连接的一个标…

前端pointer-events属性

1.如图 2.用法 使用pointer-events来阻止元素成为鼠标事件目标不一定意味着元素上的事件侦听器永远不会触发。如果元素后代明确指定了pointer-events属性并允许其成为鼠标事件的目标,那么指向该元素的任何事件在事件传播过程中都将通过父元素,并以适当的…

golang连接sm3认证加密(app)

文章目录 环境文档用途详细信息 环境 系统平台:Linux x86-64 Red Hat Enterprise Linux 7 版本:4.5 文档用途 golang连接安全版sm3认证加密数据库,驱动程序详见附件。 详细信息 1.下载Linux golang安装包 go1.17.3.linux-amd64.tar.gz 1.1. 解压安…

PYTHON调用讯飞C/C++动态库实现离线语音合成并且实时播放

语音合成(Text-to-Speech, TTS)技术在现代应用中扮演着越来越重要的角色,从智能客服到有声读物,从导航系统到辅助工具,TTS技术无处不在。本文将详细介绍如何使用Python结合科大讯飞的离线SDK实现一个本地化的语音合成系统。 技术背景 离线语…

【Unity】模型渐变技术 BlendShapes变形

模型fbx拖拽到场景并赋予脚本上SkinnedMeshRenderer参数 按下空格即可演示渐变 可去到3DsMax 或 Blender等软件制作 这种带有BlendShapes的模型 (Sphere002)是另一个模型,3DsMax叫变形器。 可参考:【技术美术百人计划】美术 3.5 BlendShape基础_哔哩哔哩…

追觅高管批员工8点下班太早 引发加班争议

近日,社交媒体上流传一封追觅内部信。信中提到,许多深圳员工晚上不到20点就下班了,而总部那边22点后还有员工在办公室。管理者建议员工即使按时下班到家也应继续工作。信中还表示,行业内的普遍标准是员工创造的价值要达到公司雇佣成本的15倍以上,并以此质问员工是否达到了…

以防长:哈马斯要么接受要么被消灭 以军全面施压加沙

当地时间5月30日,以色列国防部长卡茨通过个人社交媒体账号发表声明称,在以军强大的军事压力下,巴勒斯坦伊斯兰抵抗运动(哈马斯)将被迫选择接受美方提出的加沙停火提案,或被以色列消灭。卡茨表示,当前以军正在加沙地带全力展开行动,打击并摧毁哈马斯据点,并要求当地居民…

朱雀玄武敕令称改名事件成政治考题 高考模拟题意外现身

前不久,“00后”小伙朱雀玄武敕令申请改名为“周天紫微大帝”的新闻引起广泛关注。5月30日,他透露近期正准备参加今年高考,并在网上搜寻到的模拟考试卷中看到了关于自己改名一事的考题。朱雀玄武敕令出生于2001年,父母为他起名“朱云飞”。2025年1月,他改名为“朱雀玄武敕…

5分钟学会网络服务搭建,飞凌i.MX9352 + Linux 6.1实战示例

在“万物互联”的技术浪潮下,网络服务已成为连接物理世界与数字世界的核心纽带,它不仅赋予了终端设备“开口说话”的能力,更构建了智能设备的开发范式。 本文就将以飞凌嵌入式OK-MX9352-C开发板(搭载了在工业物联网领域广泛应用的…

超级对话2:大跨界且大综合的学问融智学应用场景述评(不同第三方的回应)之二

摘要:《人机协同文明升维行动框架》提出以HIAICI/W公式推动认知革命,构建三大落地场景:1)低成本认知增强神经接口实现300%学习效率提升;2)全球学科活动化闪电战快速转化知识体系;3)人…

AI Agent在测试设计中的应用

前言 随着AI和大模型(LLM)的诞生以及技术的成熟和普及,测试工程师不仅可以利用 AI 生成和优化测试用例,还能借助 LLM 提高测试覆盖率、减少测试设计的重复性工作,从而专注于更复杂的测试策略和质量保障。 在软件测试…

详细到用手撕transformer下半部分

之前我们讨论了如何实现 Transformer 的核心多头注意力机制,那么这期我们来完整地实现整个 Transformer 的编码器和解码器。 Transformer 架构最初由 Vaswani 等人在 2017 年的论文《Attention Is All You Need》中提出,专为序列到序列(seq2s…

Vue开发入门安装

Vue开发入门安装 版本选择剪不断,理还乱Node.js —— 类比为 Java JDKnpm —— 类比为 Maven 或 Gradlenvm —— 类比为 JDK 版本管理工具Vue.js —— 类比为 Spring Framework 或 JavaFX 下载配置下载node-v16.20.2-win-x86.zip设置环境变量打开位置,输…

leetcode刷题日记——二叉树的最近公共祖先

[ 题目描述 ]: [ 思路 ]: 两个节点的最近公共祖先具有以下特点如果祖先节点不是自身,那么两个节点一定在祖先节点的两边所以可以递归搜索树的左右子树,如果节点分布在两边,那么这个就是最近公共祖先,如果…

北京业之峰法式奶油风改造:92㎡两居打造温柔治愈之家

在当前居住空间设计日益注重实用性与美学融合的趋势下,北京业之峰近日完成一套法式奶油风住宅改造项目。整体设计在保留原始结构优势的基础上,以清新柔和的视觉风格和合理的空间动线布局,为业主提供了一个兼具温度与功能的理想居所。项目整体…

五星级酒店技能比赛主持稿串词

男:尊敬的各位领导~ 女:紫澜门国际酒店的兄弟姐妹们~ 合:大家——上午好~ 男:欢迎大家来到紫澜门国际酒店20XX年度——酒店竞技比赛的现场。 女:我是质检招聘部副主任XXX 男:我是工程部XXX 女:非常兴奋能兴奋能担负今天竞技比赛的主持人&…

DistilQwen-ThoughtX:变长思维链推理模型,超越DeepSeek蒸馏模型

作者:蔡文睿(清素)、汪诚愚(熊兮)、严俊冰(玖烛)、黄俊(临在) 前言 近年来,自然语言处理(NLP)领域以大语言模型(LLM&…

困在办公室二手烟中的职场人 防毒面具下的无奈抗争

早上8点,王海推开办公室的门,熟练地从衣柜里取出那套“工服”——这是他的“二手烟专用装备”。衣服早已浸透了焦油味,他迅速换上,等待同事们的到来。在这个四人办公室里,王海是唯一不抽烟的人。而他的三位同事,从清晨到傍晚,随时可能点燃一支烟,让狭小的空间瞬间烟雾弥…

《歌手》白举纲进步 遗憾止步舞台

《歌手2025》第三期竞演在湖南卫视和芒果TV落下帷幕。查理普斯作为“袭榜歌手”登场,终于实现了他推迟一年的中国行,并且成功袭榜,战胜了单依纯,而白举纲则被淘汰。节目开场时,查理普斯弹唱了《See you again》,网友纷纷感叹他的表现非常稳定。作为首位袭榜歌手,查理普斯…