| name | odoo-19-development |
| description | Odoo 19 开发权威指南。包含 Python/XML/JS (OWL 2.0) 最佳实践、项目结构规范、测试指引及代码模板。适用于构建高质量企业级应用。 |
Odoo 19 开发技能指南
1. 核心规范与环境
1.1 环境要求
- Python: 推荐 3.10+ (Odoo 19 标准)。
- PostgreSQL: 推荐 14+。
- Browser: Chrome/Firefox 最新版 (支持 OWL 开发调试)。
1.2 项目结构 (Standard Structure)
遵循官方建议的模块结构,确保清晰可维护。
my_module/
├── __init__.py
├── __manifest__.py # 模块元数据
├── models/ # Python 业务模型
│ ├── __init__.py
│ └── my_model.py
├── views/ # XML 视图与动作
│ ├── my_model_views.xml
│ └── menus.xml
├── security/ # 权限控制
│ ├── ir.model.access.csv
│ └── security.xml
├── data/ # 演示/预置数据
│ └── data.xml
├── reports/ # QWeb 报表
│ ├── report_action.xml
│ └── report_template.xml
├── static/ # 静态资源 (JS/CSS/Images)
│ ├── description/
│ │ └── icon.png
│ └── src/
│ ├── components/
│ └── xml/
└── tests/ # 自动化测试
├── __init__.py
└── test_flow.py
2. Python 开发规范 (Post-17/18 Changes)
2.1 ORM 最佳实践
- 避免直接 SQL: 除非性能瓶颈严重,否则坚持使用 ORM。
- 禁止手动 Commit: 严禁在业务代码中使用
cr.commit(),事务由框架统一管理。
- 批量操作: 使用
create (list of dicts) 而非循环 create。
- 记录集操作: 优先使用 Python 集合操作符或
filtered, mapped, sorted。
records = self.search([('state', '=', 'draft')])
active_records = records.filtered(lambda r: r.active)
names = active_records.mapped('name')
for r in records:
if r.active:
...
2.2 装饰器与方法
@api.depends: 必须列出所有依赖字段,确保计算正确触发。
@api.constrains: 用于数据一致性校验,抛出 ValidationError。
@api.model: 用于不需要记录集上下文的方法(类似静态方法)。
- New API: 不再使用旧版 API (
cr, uid, ids, context),全能 self 对象包含 env, cr, uid。
3. XML 与视图设计
3.1 命名约定
- View ID:
{model_name}_view_{view_type} (e.g., sale_order_view_form).
- Action ID:
action_{model_name}.
- Menu ID:
menu_{model_name}_{category}.
3.2 关键变更 (Odoo 17/18/19+)
- QWeb Output: 使用
t-out 替代已废弃的 t-esc。
- Wrappers: 尽量减少无意义的
div 嵌套,使用 Flex/Grid 布局。
- Kanban: 使用
<t t-name="card"> 定义卡片结构,推荐使用语义化标签 <aside> (侧边/图片), <main> (内容), <footer> (底部动作)。
3.3 视图类型
- Form: 使用
<sheet>, <group>, <notebook> 组织布局。Statusbar 放在 header。
- Tree: 默认为不可编辑,如需行内编辑设置
editable="top/bottom".
- Search: 必须包含
<field> (搜索框) 和 <filter> (预设过滤/分组)。
4. Javascript & OWL 2.0
Odoo 19 前端全面基于 OWL 2.0 组件化框架。
4.1 核心概念
组件 (Component)
import { Component, useState, onWillStart } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
export class MyComponent extends Component {
static template = "my_module.MyComponent";
static props = {
value: { type: Number, optional: true },
onClick: { type: Function, optional: true },
};
setup() {
this.state = useState({ count: this.props.value || 0 });
this.orm = useService("orm");
onWillStart(async () => {
this.partners = await this.orm.searchRead("res.partner", [], ["name"], { limit: 5 });
});
}
increment() {
this.state.count++;
if (this.props.onClick) {
this.props.onClick(this.state.count);
}
}
}
registry.category("actions").add("my_module.action_my_component", MyComponent);
常用 Hooks
useState: 创建响应式状态,UI 随状态变化自动更新。
useRef: 获取 DOM 元素或组件实例的引用。
useService: 获取 Odoo 核心服务 (orm, rpc, notification, action, dialog 等)。
onWillStart: 组件挂载前执行异步操作 (如加载数据)。
onMounted: 组件挂载后执行 (如初始化第三方库)。
4.2 Odoo 核心服务
- orm: 执行后端 CRUD 操作 (
call, searchRead, create, write).
- action: 执行动作 (
doAction).
- notification: 显示通知 (
add).
- dialog: 弹出对话框 (
add).
- rpc: 底层 RPC 调用 (通常推荐用
orm).
4.3 最佳实践
- 静态资源结构:
- JS:
static/src/components/my_component/my_component.js
- XML:
static/src/components/my_component/my_component.xml
- SCSS:
static/src/components/my_component/my_component.scss
- Props 校验: 始终定义
static props 以明确组件契约。
- 模板分离: 不要使用行内模板,将 XML 放在独立文件中。
- 继承: 使用
patch 函数扩展现有组件,而非类继承。
5. 报表 (Reports)
- 使用
ir.actions.report 定义报表动作。
- 使用 QWeb 模板定义布局,支持继承
web.html_container 和 web.external_layout。
- PDF 生成: 依赖
wkhtmltopdf,注意 CSS 分页控制 (page-break-inside: avoid).
6. 测试 (Testing)
- TransactionCase: 每个测试方法运行在独立事务中,结束后回滚。
- Common Setup: 使用
setUpClass 进行耗时的数据准备。
- Tagged: 使用
@tagged('post_install', '-at_install') 控制测试运行时机。
from odoo.tests import TransactionCase, tagged
@tagged('post_install', '-at_install')
class TestMyFlow(TransactionCase):
def test_creation(self):
record = self.env['my.model'].create({'name': 'Test'})
self.assertTrue(record.active)