Odoo の技術スタック解説 — Python+OWL+PostgreSQL
Odoo 19 Community が何で動いているかを、実際のコンテナの中で版を確かめながら説明します。画面の OWL、Python のサーバー、PostgreSQL、通知と裏の処理の仕組みまで。
目次
目次
このページには目次がありません

Odoo は、Python のサーバー、OWL という JavaScript の画面の仕組み、PostgreSQL のデータベースの 3 つで動いています。足りない機能をアドオンで足すときも、どこに何を書くかはこの 3 つの分担で決まります。
この記事の版や数は、当社の検証用の Odoo(公式のイメージ odoo:19.0・Odoo Server 19.0-20261015)のコンテナの中で、コマンドを叩いて確かめた物です。
全体の形
| 層 | 中身 | 確かめた版 |
|---|---|---|
| 画面 | OWL(JavaScript の部品+XML のテンプレート) | OWL 2.8.4 |
| サーバー | Odoo(Python)。HTTP は Werkzeug、PDF は wkhtmltopdf | Odoo Server 19.0-20261015・Python 3.12.3 |
| データベース | PostgreSQL(psycopg2 で接続) | PostgreSQL 16.15 |
Odoo 19 は Python 3.10 以上、PostgreSQL 13 以上を求めます(起動時に版を確かめる処理が入っています)。データベースは PostgreSQL だけで、ほかのデータベースは選べません。
サーバー:Python の Odoo
サーバーは 1 つの Python のプログラムで、次の物をまとめて持っています。
- HTTP の受け口:画面からの呼び出しは
/web/dataset/call_kw(JSON-RPC)、外のシステムからは/json/2/<モデル>/<メソッド>で受けます - ORM:受注・請求・品目などのモデルを Python のクラスで書き、表の作成や列の追加は Odoo が行います。見本の会社(販売・購買・在庫・会計・製造・経費を入れた状態)では、テーブルが 641 ありました
- アドオン:公式の配布物には 692 個のモジュールが入っていて、販売も在庫も同じ形のアドオンです
主な Python のライブラリは、psycopg2 2.9.9(PostgreSQL への接続)、Werkzeug 3.0.1(HTTP)、lxml 5.2.1(画面の XML)、reportlab 4.1.0、gevent 24.2.1(通知の待ち受け)でした。帳票の PDF は、HTML で組んだ帳票を wkhtmltopdf 0.12.6.1 で PDF にしています。
アドオンの書き方は「本格拡張はアドオンで — Odoo の拡張開発の基本」で説明しています。
画面:OWL
Odoo の画面は、Odoo 社が作った OWL という仕組みで組まれています。部品を JavaScript のクラスで書き、見た目を XML のテンプレートで書く形です。web アドオンの画面のソース(static/src)では、526 本の JS ファイルのうち 228 本が @odoo/owl から部品を読み込んでいました。
たとえばチェックボックスの部品は、次のように書かれています(公式のソースから抜粋)。
import { Component } from "@odoo/owl";
export class CheckBox extends Component {
static template = "web.CheckBox";
static props = {
value: { type: Boolean, optional: true },
disabled: { type: Boolean, optional: true },
onChange: { type: Function, optional: true },
};
}
<t t-name="web.CheckBox">
<div class="o-checkbox form-check" t-on-click="onClick">
<input type="checkbox" class="form-check-input"
t-att-checked="props.value" t-att-disabled="props.disabled"/>
<label class="form-check-label"><t t-slot="default"/></label>
</div>
</t>
アドオンで画面を変えるときも、この XML のテンプレートを継承して足します。公式のファイルは書き換えません。
ポイント!
当社は、日本の業務向けの画面を Vue3+TypeScript で作り、Odoo の中に載せる形も試しています。Odoo のメニューから開くと、その画面だけ Vue の部品を読み込んで表示し、閉じると片付けます。データは Odoo のサーバーに JSON-RPC で聞くので、権限や数字は Odoo の画面と同じです。OWL の画面と Vue の画面は、同じメニューの中に並べられます。
通知:PostgreSQL の LISTEN / NOTIFY
ほかの人が更新した内容やチャットのメッセージは、画面を読み直さなくても届きます。Odoo では、この通知を PostgreSQL の LISTEN / NOTIFY で受け渡しています。
- サーバーの処理が、通知を
busアドオンの表に書き、NOTIFY imbusを送る - 通知の待ち受け役が
LISTEN imbusで受け取る - 開いている画面へ
/websocketで届ける
通知のためにキューのサーバーや Node.js のサーバーを別に立てる必要はなく、PostgreSQL と Odoo のサーバーだけで完結します。
裏の処理:ir.cron
メールの取り込みや、たまった送信待ちのメールを送るような時間のかかる処理は、定期処理(ir.cron)として裏で動かします。見本の会社のデータベースには、公式のアドオンが入れた定期処理が 32 件あり、うち 25 件が有効でした。定期処理を動かすスレッドは、既定で 2 つです。
アドオンで足すときは、定期処理の行を XML で配り、処理そのものはモデルのメソッドに書きます。すぐに動かしたいときは、その定期処理を _trigger() で呼び起こします。
1 台から、分けて増やすまで
設定の workers が 0 のとき(今回の検証用もこの形)、Odoo は 1 つのプロセスの中で、HTTP・通知・定期処理をスレッドで動かします。小さく始めるなら、Odoo のサーバー 1 台と PostgreSQL で足ります。
workers を 1 以上にすると、形が変わります。
| 役 | 受け持つ物 |
|---|---|
| HTTP のワーカー | 画面と外のシステムからの呼び出し(workers の数だけ立つ) |
| 定期処理のワーカー | ir.cron の処理 |
| 通知のプロセス | gevent で websocket を待ち受ける(既定のポート 8072) |
人が増えたら HTTP のワーカーを、裏の処理が重くなったら定期処理のワーカーを増やします。前にリバースプロキシを置き、/websocket だけ通知のプロセスへ振り分けます。データベースは PostgreSQL なので、バックアップやレプリカは PostgreSQL の道具をそのまま使えます。
まとめ
- Odoo は Python のサーバー、OWL の画面、PostgreSQL の 3 つで動く
- 通知は PostgreSQL の LISTEN / NOTIFY、裏の処理は ir.cron。別のサーバーを足さずに始められる
- 増やすときは
workersで、HTTP・定期処理・通知を別のプロセスに分ける - 足すときは、どの層もアドオンで継承して足す。公式のソースは書き換えない
版を上げても足した物が動き続ける作り方は「アップデートしても壊れない — Odoo の拡張の作り方」にまとめています。