odoo-oca-developer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOdoo OCA Developer
Odoo OCA 开发者指南
Expert assistant for Odoo module development following OCA conventions and best practices.
遵循OCA规范和最佳实践的Odoo模块开发专业助手。
Core Capabilities
核心能力
1. Module Creation
1. 模块创建
Create new Odoo modules from OCA template with proper structure and conventions.
Quick Start:
bash
python scripts/init_oca_module.py my_module_name --path /path/to/addons --version 17.0What this provides:
- Complete OCA-compliant directory structure
- Pre-configured with required keys
__manifest__.py - README structure following OCA guidelines
- Proper imports
__init__.py - Example model, view, and security files
Module naming conventions:
- Use singular form: (not
sale_order_import)sale_orders_import - For base modules: prefix with (e.g.,
base_)base_location_nuts - For localization: prefix with (e.g.,
l10n_CC_)l10n_es_pos - For extensions: prefix with parent module (e.g., )
mail_forward - For combinations: Odoo module first (e.g., )
crm_partner_firstname
从OCA模板创建符合规范结构的新Odoo模块。
快速开始:
bash
python scripts/init_oca_module.py my_module_name --path /path/to/addons --version 17.0包含内容:
- 完整的符合OCA规范的目录结构
- 预配置的,包含必填字段
__manifest__.py - 遵循OCA指南的README结构
- 正确的导入配置
__init__.py - 示例模型、视图和安全文件
模块命名规范:
- 使用单数形式:(而非
sale_order_import)sale_orders_import - 基础模块:以为前缀(例如:
base_)base_location_nuts - 本地化模块:以为前缀(例如:
l10n_CC_)l10n_es_pos - 扩展模块:以父模块为前缀(例如:)
mail_forward - 组合模块:先写Odoo模块名(例如:)
crm_partner_firstname
2. Module Structure
2. 模块结构
Follow OCA conventions strictly. Reference oca_conventions.md for detailed guidelines.
Essential structure:
module_name/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── __init__.py
│ └── <model_name>.py
├── views/
│ └── <model_name>_views.xml
├── security/
│ ├── ir.model.access.csv
│ └── <model_name>_security.xml
├── data/
│ └── <model_name>_data.xml
├── readme/
│ ├── DESCRIPTION.rst
│ ├── USAGE.rst
│ └── CONTRIBUTORS.rst
└── tests/
├── __init__.py
└── test_<feature>.pyKey principles:
- One file per model:
models/sale_order.py - Views match model names:
views/sale_order_views.xml - Demo data has suffix:
_demodemo/sale_order_demo.xml - Migrations in versioned folders:
migrations/17.0.1.0.0/
严格遵循OCA规范。详细指南请参考oca_conventions.md。
基础结构:
module_name/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── __init__.py
│ └── <model_name>.py
├── views/
│ └── <model_name>_views.xml
├── security/
│ ├── ir.model.access.csv
│ └── <model_name>_security.xml
├── data/
│ └── <model_name>_data.xml
├── readme/
│ ├── DESCRIPTION.rst
│ ├── USAGE.rst
│ └── CONTRIBUTORS.rst
└── tests/
├── __init__.py
└── test_<feature>.py核心原则:
- 一个模型对应一个文件:
models/sale_order.py - 视图名称与模型匹配:
views/sale_order_views.xml - 演示数据以为后缀:
_demodemo/sale_order_demo.xml - 迁移文件放在版本化文件夹中:
migrations/17.0.1.0.0/
3. OCA Conventions Compliance
3. OCA规范合规
manifest.py essentials:
python
{
'name': 'Module Name',
'version': '17.0.1.0.0', # {odoo}.x.y.z format
'category': 'Sales',
'license': 'AGPL-3', # or LGPL-3
'author': 'Your Company, Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/<repository>',
'depends': ['base', 'sale'],
'data': [
'security/ir.model.access.csv',
'views/model_name_views.xml',
],
'installable': True,
}Python code structure:
python
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class SaleOrder(models.Model):
_inherit = 'sale.order'
# Fields
custom_field = fields.Char(string="Custom Field")
# Compute methods
@api.depends('order_line')
def _compute_total(self):
for order in self:
order.total = sum(order.order_line.mapped('price_total'))
# Business methods
def action_custom(self):
self.ensure_one()
# ImplementationXML naming conventions:
- Views: (e.g.,
<model_name>_view_<type>)sale_order_view_form - Actions: (e.g.,
<model_name>_action)sale_order_action - Menus:
<model_name>_menu - Groups:
<model_name>_group_<name> - Demo: suffix with
_demo
manifest.py 必备内容:
python
{
'name': 'Module Name',
'version': '17.0.1.0.0', # {odoo}.x.y.z 格式
'category': 'Sales',
'license': 'AGPL-3', # 或 LGPL-3
'author': 'Your Company, Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/<repository>',
'depends': ['base', 'sale'],
'data': [
'security/ir.model.access.csv',
'views/model_name_views.xml',
],
'installable': True,
}Python代码结构:
python
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class SaleOrder(models.Model):
_inherit = 'sale.order'
# Fields
custom_field = fields.Char(string="Custom Field")
# Compute methods
@api.depends('order_line')
def _compute_total(self):
for order in self:
order.total = sum(order.order_line.mapped('price_total'))
# Business methods
def action_custom(self):
self.ensure_one()
# ImplementationXML命名规范:
- 视图:(例如:
<model_name>_view_<type>)sale_order_view_form - 动作:(例如:
<model_name>_action)sale_order_action - 菜单:
<model_name>_menu - 分组:
<model_name>_group_<name> - 演示数据:以为后缀
_demo
4. Module Migration with OpenUpgrade
4. 使用OpenUpgrade进行模块迁移
Migrate modules between Odoo versions following OpenUpgrade patterns. See openupgrade_migration.md for complete guide.
Migration structure:
module_name/
└── migrations/
└── 17.0.1.0.0/
├── pre-migration.py
├── post-migration.py
└── noupdate_changes.xmlPre-migration example:
python
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
# Rename fields before module loads
openupgrade.rename_fields(env, [
('sale.order', 'sale_order', 'old_field', 'new_field'),
])
# Rename models
openupgrade.rename_models(env.cr, [
('old.model', 'new.model'),
])Post-migration example:
python
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
# Map old values to new
openupgrade.map_values(
env.cr,
openupgrade.get_legacy_name('state'),
'state',
[('draft', 'pending'), ('confirm', 'confirmed')],
table='sale_order',
)
# Recompute fields
env['sale.order'].search([])._compute_total()Common migration tasks:
- Rename fields:
openupgrade.rename_fields() - Rename models:
openupgrade.rename_models() - Rename tables:
openupgrade.rename_tables() - Map values:
openupgrade.map_values() - Delete obsolete data:
openupgrade.delete_records_safely_by_xml_id()
遵循OpenUpgrade模式在不同Odoo版本间迁移模块。完整指南请参考openupgrade_migration.md。
迁移结构:
module_name/
└── migrations/
└── 17.0.1.0.0/
├── pre-migration.py
├── post-migration.py
└── noupdate_changes.xml预迁移示例:
python
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
# Rename fields before module loads
openupgrade.rename_fields(env, [
('sale.order', 'sale_order', 'old_field', 'new_field'),
])
# Rename models
openupgrade.rename_models(env.cr, [
('old.model', 'new.model'),
])后迁移示例:
python
from openupgradelib import openupgrade
@openupgrade.migrate()
def migrate(env, version):
# Map old values to new
openupgrade.map_values(
env.cr,
openupgrade.get_legacy_name('state'),
'state',
[('draft', 'pending'), ('confirm', 'confirmed')],
table='sale_order',
)
# Recompute fields
env['sale.order'].search([])._compute_total()常见迁移任务:
- 重命名字段:
openupgrade.rename_fields() - 重命名模型:
openupgrade.rename_models() - 重命名表:
openupgrade.rename_tables() - 映射值:
openupgrade.map_values() - 删除过时数据:
openupgrade.delete_records_safely_by_xml_id()
5. Module Extension
5. 模块扩展
Extend core Odoo modules following OCA patterns.
Inherit existing model:
python
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
custom_field = fields.Char(string="Custom Info")Extend existing view:
xml
<record id="res_partner_view_form" model="ir.ui.view">
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='email']" position="after">
<field name="custom_field"/>
</xpath>
</field>
</record>Module dependencies:
- Always declare dependencies in
__manifest__.py - Use key for Odoo core/OCA modules
depends - Use for Python packages
external_dependencies - Document installation requirements in README
遵循OCA模式扩展Odoo核心模块。
继承现有模型:
python
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
custom_field = fields.Char(string="Custom Info")扩展现有视图:
xml
<record id="res_partner_view_form" model="ir.ui.view">
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='email']" position="after">
<field name="custom_field"/>
</xpath>
</field>
</record>模块依赖:
- 始终在中声明依赖
__manifest__.py - 使用字段指定Odoo核心/OCA模块
depends - 使用字段指定Python包
external_dependencies - 在README中记录安装要求
6. Validation and Quality
6. 验证与质量
Validate module structure:
bash
python scripts/validate_module.py /path/to/moduleWhat is checked:
- Required files presence (,
__init__.py)__manifest__.py - Manifest completeness (required keys)
- OCA author attribution
- License compliance (AGPL-3 or LGPL-3)
- Version format (x.y.z.w.v)
- File naming conventions
- Directory structure
Code quality tools:
bash
undefined验证模块结构:
bash
python scripts/validate_module.py /path/to/module检查内容:
- 必填文件是否存在(、
__init__.py)__manifest__.py - 清单文件是否完整(必填字段)
- OCA作者署名
- 许可证合规性(AGPL-3或LGPL-3)
- 版本格式(x.y.z.w.v)
- 文件命名规范
- 目录结构
代码质量工具:
bash
undefinedInstall pre-commit for OCA checks
Install pre-commit for OCA checks
pip install pre-commit
pre-commit install
pip install pre-commit
pre-commit install
Run checks
Run checks
pre-commit run --all-files
pre-commit run --all-files
Run specific checks
Run specific checks
flake8 module_name/
pylint --load-plugins=pylint_odoo module_name/
undefinedflake8 module_name/
pylint --load-plugins=pylint_odoo module_name/
undefinedWorkflow Decision Tree
工作流决策树
"I need to create a new Odoo module"
→ Use to generate OCA-compliant structure
→ Edit with module details
→ Create models in directory
→ Create views in directory
→ Add security rules in
→ Update documentation
→ Run validation:
scripts/init_oca_module.py__manifest__.pymodels/views/security/readme/scripts/validate_module.py"I need to migrate a module to a new Odoo version"
→ Check OpenUpgrade for breaking changes
→ Create migration folder:
→ Write pre-migration script for schema changes
→ Write post-migration script for data transformation
→ Test on copy of production database
→ Reference openupgrade_migration.md
migrations/<new_version>/"I need to extend a core Odoo module"
→ Create new module with core module in
→ Use to extend models
→ Use to extend views
→ Follow OCA naming:
→ Keep changes minimal and focused
depends_inheritinherit_id<core_module>_<feature>"I'm not sure if my module follows OCA conventions"
→ Run
→ Check oca_conventions.md
→ Review manifest.py for required keys
→ Verify file naming and structure
→ Ensure OCA author attribution
scripts/validate_module.py“我需要创建一个新的Odoo模块”
→ 使用生成符合OCA规范的结构
→ 编辑填写模块详情
→ 在目录中创建模型
→ 在目录中创建视图
→ 在中添加安全规则
→ 更新中的文档
→ 运行验证:
scripts/init_oca_module.py__manifest__.pymodels/views/security/readme/scripts/validate_module.py“我需要将模块迁移到新的Odoo版本”
→ 查看OpenUpgrade的破坏性变更
→ 创建迁移文件夹:
→ 编写预迁移脚本处理架构变更
→ 编写后迁移脚本处理数据转换
→ 在生产数据库副本上测试
→ 参考openupgrade_migration.md
migrations/<new_version>/“我需要扩展Odoo核心模块”
→ 创建新模块并在中声明核心模块
→ 使用扩展模型
→ 使用扩展视图
→ 遵循OCA命名规范:
→ 保持变更最小且聚焦
depends_inheritinherit_id<core_module>_<feature>“我不确定我的模块是否符合OCA规范”
→ 运行
→ 查看oca_conventions.md
→ 检查的必填字段
→ 验证文件命名和结构
→ 确保包含OCA作者署名
scripts/validate_module.py__manifest__.pyResources
资源
scripts/
scripts/
- init_oca_module.py: Create new Odoo module with OCA-compliant structure
- validate_module.py: Validate module against OCA conventions
- init_oca_module.py:创建符合OCA规范的新Odoo模块
- validate_module.py:验证模块是否符合OCA规范
references/
references/
- oca_conventions.md: Complete OCA coding standards and module structure guidelines
- openupgrade_migration.md: OpenUpgrade migration patterns and best practices
- oca_conventions.md:完整的OCA编码标准和模块结构指南
- openupgrade_migration.md:OpenUpgrade迁移模式和最佳实践
assets/
assets/
- module_template/: Official OCA module template with complete directory structure
- module_template/:官方OCA模块模板,包含完整目录结构
Best Practices
最佳实践
Module Development
模块开发
- Start with OCA template:
scripts/init_oca_module.py - Follow naming conventions strictly
- One file per model
- Keep models, views, and data separate
- Use meaningful xmlids following OCA patterns
- Include comprehensive tests
- Document in readme/ folder
- 从OCA模板开始:
scripts/init_oca_module.py - 严格遵循命名规范
- 一个模型对应一个文件
- 将模型、视图和数据分离
- 使用符合OCA模式的有意义xmlid
- 包含全面的测试
- 在readme/文件夹中编写文档
Code Quality
代码质量
- Follow PEP8 for Python code
- Use 4-space indentation in XML
- No SQL injection vulnerabilities
- Never bypass ORM without justification
- Never commit transactions manually
- Use for import errors
_logger.debug() - Handle external dependencies properly
- Python代码遵循PEP8规范
- XML使用4空格缩进
- 避免SQL注入漏洞
- 除非必要,否则不要绕过ORM
- 不要手动提交事务
- 使用记录导入错误
_logger.debug() - 正确处理外部依赖
Git Commits
Git提交
Format:
[TAG] module_name: short summaryCommon tags:
- - New feature/module
[ADD] - - Bug fix
[FIX] - - Refactoring
[REF] - - Improvement
[IMP] - - Migration
[MIG] - - Removal
[REM]
格式:
[TAG] module_name: 简短摘要常见标签:
- - 新功能/模块
[ADD] - - 修复Bug
[FIX] - - 重构
[REF] - - 改进
[IMP] - - 迁移
[MIG] - - 删除
[REM]
Migration Strategy
迁移策略
- Study OpenUpgrade analysis for target version
- Check for breaking changes in core modules
- Test on database copy first
- Write pre-migration for schema changes
- Write post-migration for data transformation
- Document breaking changes in README
- Update version following semantic versioning
- 研究目标版本的OpenUpgrade分析
- 检查核心模块的破坏性变更
- 先在数据库副本上测试
- 编写预迁移脚本处理架构变更
- 编写后迁移脚本处理数据转换
- 在README中记录破坏性变更
- 遵循语义化版本更新版本号
Common Patterns
常见模式
Pattern: Add computed field with dependencies
模式:添加带依赖的计算字段
python
total = fields.Float(compute='_compute_total', store=True)
@api.depends('line_ids.amount')
def _compute_total(self):
for record in self:
record.total = sum(record.line_ids.mapped('amount'))python
total = fields.Float(compute='_compute_total', store=True)
@api.depends('line_ids.amount')
def _compute_total(self):
for record in self:
record.total = sum(record.line_ids.mapped('amount'))Pattern: Extend view safely
模式:安全扩展视图
xml
<xpath expr="//field[@name='partner_id']" position="after">
<field name="custom_field"/>
</xpath>xml
<xpath expr="//field[@name='partner_id']" position="after">
<field name="custom_field"/>
</xpath>Pattern: Add security group
模式:添加安全组
xml
<record id="group_custom" model="res.groups">
<field name="name">Custom Access</field>
<field name="category_id" ref="base.module_category_sales"/>
</record>xml
<record id="group_custom" model="res.groups">
<field name="name">Custom Access</field>
<field name="category_id" ref="base.module_category_sales"/>
</record>Pattern: Migration with value mapping
模式:带值映射的迁移
python
openupgrade.map_values(
env.cr,
openupgrade.get_legacy_name('old_field'),
'new_field',
[('old_value', 'new_value')],
table='model_table',
)python
openupgrade.map_values(
env.cr,
openupgrade.get_legacy_name('old_field'),
'new_field',
[('old_value', 'new_value')],
table='model_table',
)Troubleshooting
故障排除
Module not appearing in Apps
- Check in manifest.py
'installable': True - Verify init.py imports
- Run:
odoo-bin -u module_name -d database
Import errors
- Add try-except for external dependencies
- Document installation in readme/INSTALL.rst
- Add to requirements.txt for Python packages
Migration fails
- Check pre-migration runs before module load
- Verify table/column names with in psql
\d table - Use for debugging
openupgrade.logged_query() - Test on copy database first
Tests failing
- Use
tagged('post_install', '-at_install') - Test with minimal user permissions using
@users() - Avoid dynamic dates, use
freezegun - Mock external services
模块未在应用列表中显示
- 检查中
__manifest__.py是否设置'installable': True - 验证的导入配置
__init__.py - 运行:
odoo-bin -u module_name -d database
导入错误
- 为外部依赖添加try-except块
- 在readme/INSTALL.rst中记录安装要求
- 将依赖添加到requirements.txt中
迁移失败
- 检查预迁移脚本是否在模块加载前运行
- 使用psql的验证表/列名称
\d table - 使用进行调试
openupgrade.logged_query() - 先在副本数据库上测试
测试失败
- 使用
tagged('post_install', '-at_install') - 使用以最小用户权限测试
@users() - 避免使用动态日期,使用
freezegun - 模拟外部服务
Quick Reference
快速参考
Create module:
bash
python scripts/init_oca_module.py my_module --version 17.0Validate module:
bash
python scripts/validate_module.py path/to/moduleCheck conventions:
See oca_conventions.md
Migration guide:
See openupgrade_migration.md
Module template:
Copy from assets/module_template/
创建模块:
bash
python scripts/init_oca_module.py my_module --version 17.0验证模块:
bash
python scripts/validate_module.py path/to/module查看规范:
参考oca_conventions.md
迁移指南:
参考openupgrade_migration.md
模块模板:
从assets/module_template/复制