OdooのORMやビューを触っていると、どこかで必ずcontextという語を目にします。フィールド定義やXMLの属性、Pythonコードのあちこちで現れ、普段は気にせず使えても、意図しない動きをすると途端に調査が必要になる――そんな存在です。
コンテキストの仕組みを理解することは単なる理屈ではありません。フォームの初期値、レコードの絞り込み、計算フィールドの振る舞いに直接影響するため、簡単なOdooカスタマイズからモジュール開発まで、正しく扱うとデバッグの工数が大幅に減ります。
本稿では、コンテキストとは何か、Odooの仕組みの中でどのように伝搬するのか、実務でどう使えばよいかを具体例を交えて解説します。
Odooでの「コンテキスト」とは何か
Odooのコンテキストは、リクエストやメソッド呼び出し、レコード操作に付随して運ばれるPythonの辞書オブジェクトです。fields.Context()のような専用フィールドは存在せず、あくまで動作を変えるための補助情報として機能します。
言い換えれば、UIやコードに見えない指示書が一緒に飛んでくるイメージです。例えば「このフィールドはこの値で初期化する」「アーカイブ済みも含める」「表示言語はこれにする」「関連レコード選択時にこの条件を使う」といった指示を運びます。
コンテキストが現れる場所
Odooのデータモデル周りでコンテキストに出会う主なポイントは次の3つです:
- Pythonのフィールド定義上:Many2one/One2many/Many2manyなどのリレーションフィールドに指定する
contextパラメータ。 - XMLビューの属性:form/list/kanbanなどの
<field>タグで使うcontext属性。 - ORMの環境:Python内で
self.env.contextで参照したり、self.with_context(key=value)で変更したりするもの。
どの場面でも本質は同じで、実行時にフィールドやレコードの振る舞いを決める追加情報を運搬しているだけです。
Odooのデータモデル内でのコンテキストの働き
ユーザーがフォームを開いてからレコードを保存するまで、コンテキストはOdooの処理の流れに沿って伝播します。主要な仕組みを実務視点で見ていきましょう。
default_*で渡す初期値
最も使われるコンテキストのパターンの一つがdefault_field_nameです。キーがdefault_で始まると、新規レコード作成時にそのフィールドが事前入力されます。
例えばボタンから新しい受注フォームを開くときに{"default_partner_id": 42}を渡せば、顧客欄にID 42の取引先が既に入った状態でフォームが開きます。追加のPython処理を書かなくてもユーザーは事前入力されたフォームを受け取れます。
この手法は、レコード間のスムーズな導線を作るためのOdoo開発でよく使われます。
リレーションフィールド上のcontext
Many2one/One2many/Many2manyを定義する際、contextパラメータを渡すと、そのリレーション経由でレコードを表示・作成するときに適用されます。
実務例として、res.partnerを参照するMany2oneにcontext={"default_is_company": True}を付けると、そのフィールドから新規作成した取引先は初期状態で「法人」チェックが入ります。強制ではなくユーザーを促す設計です。
XMLビュー内のコンテキスト
ビューのXMLでcontext属性を使う場合、動的に評価できる点が大きな特徴です。別のフィールド値を参照してコンテキストを生成できます。
これにより、一つのフィールドの挙動を別のフィールドの値に応じて変えるような賢いフォームが作れます。余分なPythonを書かずにリレーションの振る舞いを調整するために重要な手法です。
Pythonでのコンテキスト参照と変更
モデル内のどんなメソッドでも現在のコンテキストはself.env.contextで読めます。呼び出し時点の辞書が返ってきます。
コンテキストを変えた状態で処理を走らせたいときはself.with_context(key=value)を使います。元のレコードセットは不変で、新しい環境を持つレコードセットが返るため、副作用を避けられます。
よく使われる組み込みコンテキストキー
Odoo本体もいくつか予約的なキーを利用しており、これらを使うとカスタムコードを書かずに動作を制御できます:
lang: 翻訳済みフィールドの表示言語を切り替える。active_test:Falseを入れるとアーカイブ済みレコードも検索結果に含める。no_recompute: 保存済みの計算フィールドの再計算を抑制する。mail_notrack: 書き込み操作でチャッターのトラッキングを無効にする。allowed_company_ids: マルチカンパニー環境でのレコード可視性を制御する。bin_size: Binaryフィールドでバイナリ本体の代わりにサイズを返す。
こうした組み込みキーを知っておくと、カスタムコードを最小化して望む振る舞いを実現できます。実装ガイドには必須の知識です。
業務での活用シーン
コンテキストは開発者だけの道具ではなく、業務フローを解決するための実務的な仕組みです。代表的な活用例を5つ紹介します。
1. CRM:新規リード作成時に営業チームを自動セット
営業マネージャーが自分のチームのカンバンから「新規」を押したとき、そのままチームが割り当てられた状態でフォームを開けると便利です。アクションのコンテキストにdefault_team_idを渡せば手動選択を省けます。
2. 販売:顧客セグメントに応じた価格表のデフォルト設定
特定の顧客カテゴリから見積を作るとき、そのカテゴリに合った価格表をdefault_pricelist_idで渡しておけば営業担当は適切な価格をすぐ選べます。選択の自由は残したまま誤入力を減らせます。
3. 在庫:振替フォームのロケーション絞り込み
倉庫作業では、出庫元ロケーションを当該倉庫に限定したい場合があります。Many2oneフィールドにドメインをコンテキスト経由で渡すことで、複数倉庫環境でも誤選択を減らせます。
4. 会計:請求書行の多言語対応
海外顧客向けに請求書を作る際、langキーで顧客の言語を指定すれば商品名や説明がその言語で表示されます。内部データが英語でも、顧客向けには翻訳された文言を見せられます。
5. カスタムモデル:特定ビューでアーカイブ品を表示
運用上、廃止品も一覧で確認したい場面がある場合、ビューのアクションにactive_test: Falseを設定すれば、そのビューだけアーカイブ品を含めて表示できます。Pythonを触らずに要件を満たせる良い例です。
フィールドに対するコンテキストの作成とカスタマイズ方法
フィールドにコンテキストを追加・変更する方法は2通りあります。ノーコードで済ませたいならOdoo Studio、細かい制御や動的挙動が必要ならPythonとXMLで実装します。これはどのOdoo技術解説にも載る基本です。
Odoo Studioの活用
Odoo Studioはコードを書かずにフィールドの一部プロパティを変更できます。リレーションフィールドでは、ユーザー操作で新規作成した際に適用するデフォルト値をコンテキストとして設定できます。
単純な事前入力(会社/担当者/カテゴリ等)であればStudioで十分ですが、他フィールドの値を参照するような動的コンテキストはサポートが限定的なため技術実装が必要になります。
Studioで設定したコンテキストはビューに直接保存されます。後から同じビューをモジュールで拡張する場合、既存のStudio設定と衝突しないよう注意が必要です。
Pythonでフィールドにコンテキストを定義する
モジュール開発では、フィールド定義時にcontextを直接指定します。Many2oneなら静的な辞書を渡す形です:
このような静的コンテキストはそのフィールドがロード・作成されるたびに適用されますが、他フィールドの値に応じて変化することはありません。レコードの状態に応じた動的挙動が必要ならビュー側で設計します。
XMLビューでのコンテキスト定義
ビューXMLのcontext属性は文字列として評価され、フィールド値や現在のユーザーID(uid)、アクティブレコードID(active_id)などを参照できます。
このためビュー側でのコンテキスト指定は柔軟性が高く、フィールド間の依存関係を持つUI振る舞いを作る際の標準的なやり方です。ユーザーにとって自然な操作感を作る上で重要な手法です。
ウィンドウアクション経由でのコンテキスト伝達
ir.actions.act_window(メニューやボタンが開くアクション)にコンテキストを設定することもできます。アクションのコンテキストはビュー読み込み時にセッションコンテキストへマージされます。
CRMのチーム自動セットの例のように、ナビゲーション文脈ごとに違う初期値を与えたいならアクションにコンテキストを置くのが最も整理された方法です。モデルコードに触れずに使い分けできます。
実務でのベストプラクティス
Odooでコンテキストを扱うときは、いくつかの習慣を守ると作業がぐっと楽になります。モジュール開発でもちょっとしたカスタマイズでも役立つ原則です。
- コンテキストは提案に使い、制約には使わない。 デフォルトはユーザーを導くためのもので、強制したい場合はドメインやonchange、制約メソッドを使いましょう。
- 動的なコンテキストはビューに置く。 フィールド定義のコンテキストは静的です。レコードの状態に応じて変わる必要があるならXMLで記述するのが正解です。
- env.contextを直接書き換えないで、with_context()を使う。 環境は不変性を前提に設計されています。副作用を避けるために
with_context()で新しい環境を生成しましょう。 - 渡すキーは厳選する。 コンテキストは呼び出しチェーンを通して積み重なるため、不必要なキーを渡すと他の処理に影響を与えることがあります。必要最小限に留めてください。
- 条件ロジック用のフラグを渡すパターンは便利。例えば
from_wizard: Trueのようなブールフラグをコンテキストで渡し、computeやonchangeで振る舞いを切り替えるとモデルに状態フィールドを増やさずに済みます。 - カスタムキーはモジュール内でドキュメント化する。 コンテキストは見えないため、独自キーを使う場合はコメントやdocstringで何を期待しているかを明記しておくと後で助かります。
よくある落とし穴
コンテキスト関連のバグはUI上に現れにくく追跡が難しいことがあります。実務でよく見るミスを以下に挙げます。
default_*を必須値と誤解すること
コンテキスト経由のデフォルトはフォームからの作成時にのみ適用されます。ORMでコード的にレコードを作成する際にコンテキストを渡さなければデフォルトは反映されません。フィールドのPythonレベルのdefaultとは性質が異なる点に注意してください。
コンテキスト辞書を直接変更すること
コンテキスト辞書は呼び出しスタックで共有されます。self.env.contextを直接いじると同一トランザクション内の他処理に悪影響を及ぼす可能性があります。常にself.with_context(new_key=value)で新しい環境を作る習慣をつけてください。
コンテキストに多くの情報を詰め込みすぎること
追加したキーはすべて呼び出しチェーンを伝わります。予期しないキーが他のメソッドの分岐をトリガーすることがあるため、必要な情報だけを渡すようにしてください。
アーカイブ済みレコード検索でactive_testを忘れること
標準ではsearch()/search_read()はアクティブなレコードのみを返します。アーカイブ済みも扱う必要がある場合は明示的にactive_test: Falseをコンテキストに渡さないと見えません。製品や在庫周りでは頻出する落とし穴です。
Studioとコードのコンテキスト衝突
Studioでビューに設定したコンテキストと、後からモジュールで追加したビュー拡張のコンテキストが競合することがあります。XMLのマージ順や既存設定を必ず確認してからカスタマイズを行ってください。
まとめ
コンテキストはOdoo内部で多くの仕事を静かにこなすメカニズムです。フィールド定義、ビュー属性、ORM環境のどこを経由して伝わるかを押さえれば、データモデルの振る舞いをより細かく制御できます。
要点をまとめるとシンプルです。default_*でユーザーを誘導し、強制はしない。動的なコンテキストはビューに置く。コンテキストを直接書き換えずwith_context()を使う。必要最小限のキーだけ渡す――これらを守れば予期せぬ干渉を減らせます。
Odooのフィールド解説を読んでいるときも、カスタムモジュールを作るときも、フィールドの不可解な挙動を追うときも、コンテキストの理解は必ず役に立ちます。
私たちDasoloは、企業がOdooを業務に合わせて導入・カスタマイズ・最適化する支援を行っています。コンテキストを含むカスタマイズで不安がある、あるいは実装方針を相談したい場合はお手伝いします。
まずは弊社の お問い合わせページ からご連絡ください。規模を問わず、御社の業務に合ったOdooの実装を一緒に設計します。