スキル一覧に戻る
unclecatvn

odoo-18

by unclecatvn

Agent Skills Documentation

0🍴 0📅 2026年1月23日
GitHubで見るManusで実行

SKILL.md


name: odoo-18 description: Complete skill guide for AI agents to write proper Odoo 18 code. This master file references detailed guides for each topic including models, fields, decorators, views, performance optimization, controllers, and development best practices. Use this skill when writing, reviewing, or refactoring Odoo 18 code to ensure proper ORM patterns, API usage, and performance optimization. globs: "**/*.{py,xml}" license: MIT author: UncleCat version: 1.0.0

Odoo 18 Skill

Complete skill guide for AI agents to write proper Odoo 18 code. This master file references detailed guides for each topic.

Quick Reference

TopicFileWhen to Use
Model Methodsodoo-18-model-guide.mdWriting ORM queries, CRUD operations
Field Typesodoo-18-field-guide.mdDefining model fields
API Decoratorsodoo-18-decorator-guide.mdUsing @api decorators
Views & XMLodoo-18-view-guide.mdWriting XML views, actions, menus
Performanceodoo-18-performance-guide.mdOptimizing queries, preventing N+1
Transactionsodoo-18-transaction-guide.mdSavepoints, UniqueViolation, commit/rollback
Controllersodoo-18-controller-guide.mdHTTP endpoints, routing
OWL Componentsodoo-18-owl-guide.mdBuilding OWL UI components
Developmentodoo-18-development-guide.mdManifest, reports, security, wizards

Model Guide

File: odoo-18-model-guide.md

When to read: Writing model methods, ORM queries, domain filters

Quick Patterns

# Search with prefetch (auto)
orders = self.search([('state', '=', 'done')])
for order in orders:
    print(order.name, order.partner_id.name)  # Partners prefetched

# search_read for dicts
data = self.search_read([('state', '=', 'done')], ['name', 'amount'])

# Batch create (Odoo 18)
records = self.create([
    {'name': f'Record {i}'}
    for i in range(100)
])

Anti-Patterns to Avoid

# BAD: search in loop (N+1)
for order in orders:
    payments = self.env['payment'].search([('order_id', '=', order.id)])

# GOOD: search with IN
payments = self.env['payment'].search_read(
    [('order_id', 'in', orders.ids)]
)

Field Guide

File: odoo-18-field-guide.md

When to read: Defining new fields, choosing field types

Quick Reference

# Monetary (always use currency_field)
amount = fields.Monetary(currency_field='company_id.currency_id')

# Computed + stored
total = fields.Float(compute='_compute_total', store=True)

# Many2one with ondelete
partner_id = fields.Many2one('res.partner', ondelete='cascade')

# Index types
code = fields.Char(index='trigram')  # Full-text search

Field Selection

NeedUse
Short textChar
Long textText
MoneyMonetary (with currency_field)
DropdownSelection
Many-to-oneMany2one (specify ondelete)
One-to-manyOne2many (specify inverse_name)
Computedcompute= (add store=True if searchable)

Decorator Guide

File: odoo-18-decorator-guide.md

When to read: Using @api decorators, compute fields, validation

Decision Tree

Need field behavior?
├── Computed from other fields → @api.depends
├── Validate data → @api.constrains
├── Prevent deletion → @api.ondelete (Odoo 18!)
├── Form UI update → @api.onchange
│
Need method behavior?
├── Model-level method → @api.model
└── Normal record method → no decorator

Key Patterns

# @api.depends with dotted paths (Odoo 18)
@api.depends('partner_id.email')
def _compute_email(self):
    for rec in self:
        rec.email = rec.partner_id.email

# @api.ondelete (Odoo 18 feature)
@api.ondelete(at_uninstall=False)
def _unlink_if_not_draft(self):
    if any(rec.state != 'draft' for rec in self):
        raise UserError("Cannot delete non-draft records")

Important Rules

  • @api.depends: CAN use dotted paths (partner_id.name)
  • @api.constrains: CANNOT use dotted paths (only simple field names)
  • @api.onchange: NO CRUD operations (no create/read/write/unlink)
  • @api.ondelete: Use instead of overriding unlink() (supports uninstall)

View Guide

File: odoo-18-view-guide.md

When to read: Writing XML views, actions, menus, QWeb templates

View Types (Odoo 18)

<!-- LIST VIEW (not tree!) -->
<list string="Records" editable="bottom" multi_edit="1">
    <field name="name" decoration-success="state == 'done'"/>
    <field name="phone" optional="show"/>
</list>

<!-- FORM VIEW -->
<form string="Record">
    <sheet>
        <div class="oe_button_box" name="button_box">
            <button name="action_confirm" type="object" class="oe_stat_button" icon="fa-check"/>
        </div>
        <group>
            <field name="name"/>
        </group>
    </sheet>
    <div class="oe_chatter">
        <field name="message_ids"/>
    </div>
</form>

<!-- SEARCH VIEW -->
<search>
    <field name="name"/>
    <filter string="Active" name="active" domain="[('active', '=', True)]"/>
    <group expand="0" string="Group By">
        <filter string="State" context="{'group_by': 'state'}"/>
    </group>
</search>

View Inheritance (XPath)

<record id="view_partner_form_inherit" model="ir.ui.view">
    <field name="inherit_id" ref="base.view_partner_form"/>
    <field name="arch" type="xml">
        <!-- Add after field -->
        <xpath expr="//field[@name='email']" position="after">
            <field name="my_field"/>
        </xpath>

        <!-- Shorthand -->
        <field name="email" position="after">
            <field name="my_field"/>
        </field>
    </field>
</record>

Odoo 18 View Changes

ChangeOldNew
List view tag<tree><list>
DecorationLimitedFull support (decoration-success, etc.)
Optional fieldsManual<field optional="show/hide"/>
Multi editLimitedmulti_edit="1" attribute

Performance Guide

File: odoo-18-performance-guide.md

When to read: Optimizing queries, fixing slow code, preventing N+1

N+1 Prevention Checklist

# ✅ GOOD: Prefetch works automatically
for order in orders:
    print(order.partner_id.name)  # Partners fetched in batch

# ❌ BAD: search in loop
for order in orders:
    partner = self.env['res.partner'].browse(order.partner_id.id)

# ❌ BAD: access without proper depends
@api.depends('partner_id')  # Missing .email
def _compute_email(self):
    for rec in self:
        rec.email = rec.partner_id.email  # N queries!

Performance Constants (Odoo 18)

PREFETCH_MAX = 1000      # Records prefetched per batch
INSERT_BATCH_SIZE = 100   # Batch insert size
UPDATE_BATCH_SIZE = 100   # Batch update size

Optimization Patterns

# Use mapped() instead of list comprehension
partner_ids = orders.mapped('partner_id.id')

# Use filtered() before operations
done_orders = orders.filtered(lambda o: o.state == 'done')

# Use search_read() for dicts
data = self.search_read(domain, ['name', 'amount'])

# Bin size for binary fields
attachments.with_context(bin_size=True).read(['datas'])

# read_group for aggregations
result = self.read_group(domain, ['amount:sum'], ['category_id'])

Transaction Guide

File: odoo-18-transaction-guide.md

When to read: Handling database errors, UniqueViolation, savepoints, commit/rollback

Quick Patterns

# Savepoint for error isolation
with self.env.cr.savepoint():
    try:
        record = self.create(data)
    except psycopg2.errors.UniqueViolation:
        pass  # Transaction still valid

# Batch create with error isolation
for data in data_list:
    with self.env.cr.savepoint():
        record = self.create(data)

# Check for duplicates before creating
existing = self.search([('email', '=', email)], limit=1)
if not existing:
    record = self.create({'email': email})

PostgreSQL Error Codes

CodeNameOdoo Handler
23502NOT NULL violationconvert_pgerror_not_null
23505UNIQUE violationconvert_pgerror_unique
23514CHECK violationconvert_pgerror_constraint
40001Serialization failureRetry with advisory lock
25P02InFailedSqlTransactionMust rollback

Transaction State Flow

Normal → [Error] → Aborted → [rollback] → Normal
                    ↓
                 [commit] → ERROR! (cannot commit aborted transaction)

Key Rule: Once a transaction enters "aborted" state due to error, all subsequent commands fail until ROLLBACK.

Common Issues

# BAD: Continuing after UniqueViolation without cleanup
try:
    record = self.create({'email': 'duplicate@email.com'})
except psycopg2.errors.UniqueViolation:
    pass  # Transaction is now ABORTED
record = self.create({'email': 'another@email.com'})  # FAILS!

# GOOD: Use savepoint
with self.env.cr.savepoint():
    try:
        record = self.create({'email': 'duplicate@email.com'})
    except psycopg2.errors.UniqueViolation:
        pass
# This now works:
record = self.create({'email': 'another@email.com'})

Controller Guide

File: odoo-18-controller-guide.md

When to read: Writing HTTP endpoints, routes, web controllers

Quick Patterns

from odoo import http
from odoo.http import request

class MyController(http.Controller):

    # JSON endpoint for frontend
    @http.route('/my/data', type='json', auth='user')
    def get_data(self):
        return request.env['my.model'].search_read([], ['name'])

    # HTTP page
    @http.route('/my/page', type='http', auth='public', website=True)
    def my_page(self):
        return request.render('my_module.template', {})

    # External API (no CSRF)
    @http.route('/api/webhook', type='http', auth='none', csrf=False)
    def webhook(self):
        return "OK"

Auth Types

AuthBehaviorUse For
auth='user'Login requiredNormal pages, internal APIs
auth='public'No login, respects ACLWebsite pages, public content
auth='none'No environment, no ACLLogin page, health checks, webhooks

OWL Guide

File: odoo-18-owl-guide.md

When to read: Building OWL components, hooks, services for frontend UI

Quick Patterns

/** @odoo-module **/
import { Component, useState, onWillStart } from "@owl/swidget";

// Basic OWL Component
class MyComponent extends Component {
    static template = "my_module.MyComponent";

    setup() {
        this.state = useState({ count: 0 });
    }

    increment() {
        this.state.count++;
    }
}

// Using ORM service
setup() {
    this.orm = useService("orm");
}

async loadRecords() {
    this.records = await this.orm.searchRead(
        "my.model",
        [["active", "=", true]],
        ["name", "date"]
    );
}

// Using RPC service
setup() {
    this.rpc = useService("rpc");
}

async callMethod() {
    await this.rpc("/my/controller", { params: {...} });
}

Key Services

ServicePurpose
ormDatabase operations (search, read, create, write)
rpcCall Python controllers / HTTP routes
actionExecute ir.actions
dialogShow modal dialogs
notificationShow toasts
routerNavigate in app

Component Lifecycle

setup() {
    onWillStart(() => {
        // Before render, async OK
        return this.loadData();
    });

    onMounted(() => {
        // After DOM ready
    });

    onWillUnmount(() => {
        // Cleanup
    });
}

Common Issues & Solutions

Issue: N+1 Queries

Symptom: Loop with search inside

# BAD
for order in orders:
    payments = self.env['payment'].search([('order_id', '=', order.id)])

Solution: Use IN domain or read_group

# GOOD
payments = self.env['payment'].search_read([('order_id', 'in', orders.ids)])

Issue: Compute Field Not Recomputing

Symptom: Stale computed value

Solution: Check @api.depends includes ALL dependencies

# BAD - missing dependency
@api.depends('partner_id')
def _compute_email(self):
    rec.email = rec.partner_id.email

# GOOD - full path
@api.depends('partner_id', 'partner_id.email')
def _compute_email(self):
    rec.email = rec.partner_id.email

Issue: Constraint Not Triggering

Symptom: @api.constrains not called

Cause: Field not in create()/write() call

Solution: Override create/write if validation always needed

@api.model_create_multi
def create(self, vals_list):
    records = super().create(vals_list)
    records._check_full_validation()
    return records

File Structure

docs/skills/odoo/18.0/
├── SKILL.md                       # THIS FILE - master reference
├── odoo-18-model-guide.md         # ORM, CRUD, search, domain
├── odoo-18-field-guide.md         # Field types, parameters
├── odoo-18-decorator-guide.md      # @api decorators
├── odoo-18-view-guide.md          # XML views, actions, menus, QWeb
├── odoo-18-performance-guide.md    # N+1 prevention, optimization
├── odoo-18-transaction-guide.md   # Savepoints, UniqueViolation, commit/rollback
├── odoo-18-controller-guide.md     # HTTP, routing, controllers
├── odoo-18-owl-guide.md           # OWL components, hooks, services
└── odoo-18-development-guide.md    # Manifest, reports, security, wizards

Development Guide

File: odoo-18-development-guide.md

When to read: Creating modules, manifest structure, reports, security, wizards

Module Structure

my_module/
├── __init__.py
├── __manifest__.py
├── models/
│   ├── __init__.py
│   └── my_model.py
├── views/
│   └── my_model_views.xml
├── security/
│   ├── ir.model.access.csv
│   └── my_module_security.xml
├── wizard/
│   ├── __init__.py
│   └── my_wizard.py
└── report/
    └── my_report_views.xml

Manifest Keys

{
    'name': 'My Module',
    'version': '18.0.1.0.0',
    'depends': ['base'],
    'data': [...],
    'installable': True,
}

Access Rights (CSV)

id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_model_user,my.model.user,model_my_model,base.group_user,1,1,1,0

Record Rules

<record id="my_model_personal" model="ir.rule">
    <field name="domain_force">[('user_id', '=', user.id)]</field>
</record>

TransientModel (Wizards)

class MyWizard(models.TransientModel):
    _name = 'my.wizard'

    def action_process(self):
        # Process selected records
        return {'type': 'ir.actions.client', 'tag': 'display_notification'}

Reports

<record id="action_report_my_model" model="ir.actions.report">
    <field name="report_type">qweb-pdf</field>
    <field name="report_name">my_module.report_my_model</field>
    <field name="binding_model_id" ref="model_my_model"/>
</record>

Base Code Reference (Odoo 18)

All guides are based on analysis of Odoo 18 base code. To reference in your project:

  • odoo/models.py - ORM implementation
  • odoo/fields.py - Field types
  • odoo/api.py - Decorators
  • odoo/http.py - HTTP layer
  • odoo/exceptions.py - Exception types

For setup instructions with different AI IDEs, see AGENTS.md

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です