odoo-oca-developer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Odoo 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.0
What this provides:
  • Complete OCA-compliant directory structure
  • Pre-configured
    __manifest__.py
    with required keys
  • README structure following OCA guidelines
  • Proper
    __init__.py
    imports
  • Example model, view, and security files
Module naming conventions:
  • Use singular form:
    sale_order_import
    (not
    sale_orders_import
    )
  • For base modules: prefix with
    base_
    (e.g.,
    base_location_nuts
    )
  • For localization: prefix with
    l10n_CC_
    (e.g.,
    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>.py
Key principles:
  • One file per model:
    models/sale_order.py
  • Views match model names:
    views/sale_order_views.xml
  • Demo data has
    _demo
    suffix:
    demo/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
  • 演示数据以
    _demo
    为后缀:
    demo/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()
        # Implementation
XML naming conventions:
  • Views:
    <model_name>_view_<type>
    (e.g.,
    sale_order_view_form
    )
  • Actions:
    <model_name>_action
    (e.g.,
    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()
        # Implementation
XML命名规范:
  • 视图:
    <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.xml
Pre-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
    depends
    key for Odoo core/OCA modules
  • Use
    external_dependencies
    for Python packages
  • 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
    中声明依赖
  • 使用
    depends
    字段指定Odoo核心/OCA模块
  • 使用
    external_dependencies
    字段指定Python包
  • 在README中记录安装要求

6. Validation and Quality

6. 验证与质量

Validate module structure:
bash
python scripts/validate_module.py /path/to/module
What 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
undefined

Install 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/
undefined
flake8 module_name/ pylint --load-plugins=pylint_odoo module_name/
undefined

Workflow Decision Tree

工作流决策树

"I need to create a new Odoo module" → Use
scripts/init_oca_module.py
to generate OCA-compliant structure → Edit
__manifest__.py
with module details → Create models in
models/
directory → Create views in
views/
directory → Add security rules in
security/
→ Update
readme/
documentation → Run validation:
scripts/validate_module.py
"I need to migrate a module to a new Odoo version" → Check OpenUpgrade for breaking changes → Create migration folder:
migrations/<new_version>/
→ Write pre-migration script for schema changes → Write post-migration script for data transformation → Test on copy of production database → Reference openupgrade_migration.md
"I need to extend a core Odoo module" → Create new module with core module in
depends
→ Use
_inherit
to extend models → Use
inherit_id
to extend views → Follow OCA naming:
<core_module>_<feature>
→ Keep changes minimal and focused
"I'm not sure if my module follows OCA conventions" → Run
scripts/validate_module.py
→ Check oca_conventions.md → Review manifest.py for required keys → Verify file naming and structure → Ensure OCA author attribution
“我需要创建一个新的Odoo模块” → 使用
scripts/init_oca_module.py
生成符合OCA规范的结构 → 编辑
__manifest__.py
填写模块详情 → 在
models/
目录中创建模型 → 在
views/
目录中创建视图 → 在
security/
中添加安全规则 → 更新
readme/
中的文档 → 运行验证:
scripts/validate_module.py
“我需要将模块迁移到新的Odoo版本” → 查看OpenUpgrade的破坏性变更 → 创建迁移文件夹:
migrations/<new_version>/
→ 编写预迁移脚本处理架构变更 → 编写后迁移脚本处理数据转换 → 在生产数据库副本上测试 → 参考openupgrade_migration.md
“我需要扩展Odoo核心模块” → 创建新模块并在
depends
中声明核心模块 → 使用
_inherit
扩展模型 → 使用
inherit_id
扩展视图 → 遵循OCA命名规范:
<core_module>_<feature>
→ 保持变更最小且聚焦
“我不确定我的模块是否符合OCA规范” → 运行
scripts/validate_module.py
→ 查看oca_conventions.md → 检查
__manifest__.py
的必填字段 → 验证文件命名和结构 → 确保包含OCA作者署名

Resources

资源

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
    _logger.debug()
    for import errors
  • Handle external dependencies properly
  • Python代码遵循PEP8规范
  • XML使用4空格缩进
  • 避免SQL注入漏洞
  • 除非必要,否则不要绕过ORM
  • 不要手动提交事务
  • 使用
    _logger.debug()
    记录导入错误
  • 正确处理外部依赖

Git Commits

Git提交

Format:
[TAG] module_name: short summary
Common tags:
  • [ADD]
    - New feature/module
  • [FIX]
    - Bug fix
  • [REF]
    - Refactoring
  • [IMP]
    - Improvement
  • [MIG]
    - Migration
  • [REM]
    - Removal
格式:
[TAG] module_name: 简短摘要
常见标签:
  • [ADD]
    - 新功能/模块
  • [FIX]
    - 修复Bug
  • [REF]
    - 重构
  • [IMP]
    - 改进
  • [MIG]
    - 迁移
  • [REM]
    - 删除

Migration Strategy

迁移策略

  1. Study OpenUpgrade analysis for target version
  2. Check for breaking changes in core modules
  3. Test on database copy first
  4. Write pre-migration for schema changes
  5. Write post-migration for data transformation
  6. Document breaking changes in README
  7. Update version following semantic versioning
  1. 研究目标版本的OpenUpgrade分析
  2. 检查核心模块的破坏性变更
  3. 先在数据库副本上测试
  4. 编写预迁移脚本处理架构变更
  5. 编写后迁移脚本处理数据转换
  6. 在README中记录破坏性变更
  7. 遵循语义化版本更新版本号

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
    'installable': True
    in manifest.py
  • 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
    \d table
    in psql
  • Use
    openupgrade.logged_query()
    for debugging
  • 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.0
Validate module:
bash
python scripts/validate_module.py path/to/module
Check 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/复制