跳轉至

建立 2026-09-14 更新 2026-09-20

開發入門

標準功能走不通、又確定不是設定問題時,再寫自訂模組(addon)。目標是:從空資料夾做出可安裝、可升級的最小模組。本頁只覆蓋最常用的 20%:清單檔、模型、檢視、權限。

先備:Python 基礎、會看 XML、Odoo 已用 Docker 跑起來(安裝)。想直接做一個完整可用的模組,請看 實作:圖書借閱模組;指令細節見 odoo-bin 指令

模組骨架

把資料夾放進 addons(或 Compose 掛載的 extra-addons),名稱用英數與底線:

my_addon/
├─ __manifest__.py
├─ __init__.py
├─ models/
│  ├─ __init__.py
│  └─ my_model.py
├─ views/
│  └─ my_model_views.xml
└─ security/
   └─ ir.model.access.csv

__manifest__.py 告訴 Odoo 這是什麼、依賴誰、要載入哪些檔:

{
    "name": "My Addon",
    "version": "18.0.1.0.0",
    "author": "Your Name",
    "license": "LGPL-3",
    "depends": ["base"],
    "data": [
        "security/ir.model.access.csv",
        "views/my_model_views.xml",
    ],
    "installable": True,
}

版本號第一段與 Odoo 大版一致(18.0)。data 的順序有差:權限必須在檢視之前,否則一般使用者打不開選單。

模型與計算欄位

# models/__init__.py
from . import my_model
# __init__.py
from . import models
# models/my_model.py
from odoo import api, fields, models


class MyModel(models.Model):
    _name = "my.model"
    _description = "My Model"

    name = fields.Char(required=True)
    amount = fields.Float()
    tax = fields.Float(compute="_compute_tax", store=True)

    @api.depends("amount")
    def _compute_tax(self):
        for rec in self:
            rec.tax = (rec.amount or 0.0) * 0.05

_name 是模型技術名稱,點號分隔。改欄位或模型後,必須升級模組-u my_addon),資料庫結構才會更新。

檢視與選單

<odoo>
  <record id="view_my_model_list" model="ir.ui.view">
    <field name="name">my.model.list</field>
    <field name="model">my.model</field>
    <field name="arch" type="xml">
      <list>
        <field name="name"/>
        <field name="amount"/>
        <field name="tax"/>
      </list>
    </field>
  </record>

  <record id="view_my_model_form" model="ir.ui.view">
    <field name="name">my.model.form</field>
    <field name="model">my.model</field>
    <field name="arch" type="xml">
      <form>
        <sheet>
          <group>
            <field name="name"/>
            <field name="amount"/>
            <field name="tax" readonly="1"/>
          </group>
        </sheet>
      </form>
    </field>
  </record>

  <record id="action_my_model" model="ir.actions.act_window">
    <field name="name">My Models</field>
    <field name="res_model">my.model</field>
    <field name="view_mode">list,form</field>
  </record>

  <menuitem id="menu_my_root" name="My App"/>
  <menuitem id="menu_my_model" name="My Models"
            parent="menu_my_root" action="action_my_model"/>
</odoo>

tree 已改名為 list

Odoo 17 起清單檢視標籤是 <list>。舊文件的 <tree> 在新版可能仍相容一段時間,新模組請寫 listview_mode 也用 list,form

權限

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

沒有 ir.model.access.csv 列,一般使用者會看到「你沒有權限」。model_my_model_name = my.model 自動對應(點改底線)。

安裝與升級

# 建立新模組骨架(也可以手動建資料夾)
docker compose run --rm odoo odoo scaffold my_addon /mnt/extra-addons

# 安裝、升級(--stop-after-init 表示做完就結束)
docker compose run --rm odoo odoo -d odoodb -i my_addon --stop-after-init
docker compose run --rm odoo odoo -d odoodb -u my_addon --stop-after-init

docker compose run 會用一個一次性容器執行,並由映像的入口程式自動帶上資料庫連線參數。若改用 docker compose exec 進入執行中的容器,要自己加 --db_host=db -r odoo -w odoo。原始碼安裝則把 odoo 換成 ./odoo-bin

或在應用程式選單先「更新應用程式清單」再安裝。改 Python 欄位、XML 或 CSV 後都要升級;只改方法內的 Python 邏輯時重啟即可,加上 --dev=reload 甚至會自動重啟。各選項的完整說明見 odoo-bin 指令

下一步

依序閱讀,每一頁都建立在前一頁之上:

  1. odoo-bin 指令:安裝、升級、shell、備份、翻譯,一次搞懂
  2. 實作:圖書借閱模組:關聯欄位、計算欄位、驗證、按鈕與狀態、群組權限
  3. 繼承與擴充_inheritxpath 檢視繼承、覆寫方法
  4. 測試與除錯:自動化測試、日誌、真實錯誤訊息速查

還沒涵蓋、知道去哪查即可:記錄規則(Record Rules)、QWeb 報表、Controller、Wizard、排程動作(Cron)。這些在官方開發者教學有完整練習,不必一次學完。

進一步學習