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)
/** @odoo-module **/
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
- JS:
- 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)