インポート可能なモジュールの書き込み¶
重要
このチュートリアルでは、 :doc:の server_framework_101
チュートリアルと :doc:の define_module_data
チュートリアルに精通しています。
しかし、開発者はモジュールを書くのにPythonのフルパワーを持つことを好みますが、そうすることはできないことがあります。 通常 Odoo のようなカスタムPythonコードの展開を許可しないマネージドホスティングソリューションです。 om platform.
However, the flexible nature of Odoo is meant to allow customizations out of the box. Whilst a lot is possible with Studio, it is also possible to define models, fields and logic in XML Data Files. This makes it easier to develop, maintain and deploy these customizations.
このチュートリアルでは、XMLデータファイルでモデル、フィールド、ロジックを定義し、それらをモジュールにまとめる方法を学びます。 これらは*インポート可能なモジュール*、または*データモジュール*と呼ばれることがあります。モジュール開発に対するこのアプローチの制限もあります。
Problem ステートメント¶
:doc:の server_framework_101
チュートリアルと同様に、不動産の概念に取り組んでいます。
私たちの目標は、 サーバーフレームワーク101 チュートリアルに似た方法で不動産資産を管理する新しいアプリケーションを作成することです。 Pythonファイルの代わりにXMLデータファイルでモデル、フィールド、ロジックを定義します。
このチュートリアルの最後に、アプリで次のことができるようになります。
販売中の不動産物件の管理
これらのプロパティをウェブサイトに公開
ウェブサイトからオンラインでオファーを承認する
プロパティが売却されたときに購入者に請求する
モジュール構造¶
どの開発プロジェクトでもそうであるように、明確な構造により、コードの管理と保守が容易になります。
Python ファイルと XML ファイルの両方を使用する標準の Odoo モジュールとは異なり、データモジュールは XML ファイルのみを使用します。 したがって、あなたの作業ツリーは次のようになります。
estate
├── actions
│ └── *.xml
├── models
│ └── *.xml
├── security
│ └── ir.model.access.csv
│ └── estate_security.xml
├── views
│ └── *.xml
├── __init__.py
└── __manifest__.py
The only Python files you will have are the __init__.py
and __manifest__.py
files.
The __manifest__.py
file will be the same as for any Odoo module, but will also import its
models in the data
list.
:file:`__manifest__.pyのセクションの`data`にあるファイルを、モデルファイルから始まる依存関係の順序でリストすることを忘れないでください。
The __init__.py
file is empty, but is required for Odoo to recognize the module if you ever
want to deploy your module in the classic way (by adding it in an addons path). It is not strictly
necessary for modules that will be imported, but it is a good practice to keep it.
モジュールのデプロイ¶
To deploy the module, you will need to create a zip file of the module and upload it to your
Odoo instance. Make sure that the module base_import_module
is installed on your instance,
then go to the and upload the zip file. You must be
in developer mode to see the Import Module
menu item.
モジュールを変更する場合は、新しいzipファイルを作成し、再度アップロードする必要があります。 モジュール内のすべてのデータをリロードします。 ただし、以前に作成したフィールドのタイプを変更するなど、一部の操作は不可能であることに注意してください。 以前のバージョンのモジュールによって作成されたデータ(削除されたフィールドなど)は自動的に削除されません。 一般的に これを処理する最も簡単な方法は、新しいデータベースから始めるか、新しいバージョンをアップロードする前にモジュールをアンインストールすることです。
モジュールをアップロードするとき、ウィザードは2つのオプションを受け付けます:
Force init
: if your module is already installed and you upload it again; このオプションをチェックすると、XMLファイル内で`noupdate="1"とマークされたすべてのデータが強制的に更新されます。デモデータをインポート
: selfexplanatory
:doc:`odoo-bin <../reference/cli>`コマンドラインツールを使用して、モジュールをデプロイすることもできます。
$ odoo-bin deploy <path_to_your_module> https://<your_odoo_instance> --login <your_login> --password <your_password>
このコマンドは、ウィザードの Force init オプションに相当する --force
オプションも受け付けます。
モジュールのデプロイに使用するユーザーには、「管理/設定」アクセス権限が必要です。
Exercise
次のようにフォルダとファイルを作成してください。
/home/$USER/src/tutorials/estate/__init__.py
/home/$USER/src/tutorials/estate/__manifest__.py
__manifest__.py`ファイルは、モジュールの名前と依存関係のみを定義する必要があります。 今のところ必要なフレームワークモジュールは ``base`
(およびbase_import_module
)だけですが、あなたのモジュールは厳密に言えば*依存*しません。 モジュールをインポートできるようにする必要があります)。モジュールのzipファイルを作成し、Odooインスタンスにアップロードします。
モデルと基本フィールド¶
想像できるように、XMLファイル内のモデルとフィールドを定義することは、Pythonほど簡単ではありません。
データファイルは順番に読み込まれるため、要素を正しい順序で定義する必要があります。 たとえば、そのモデルにフィールドを定義する前に、モデルを定義する必要があります。 を選択し、ビューにフィールドを追加する前にフィールドを定義する必要があります。
さらに、XML は Python よりもはるかに冗長なものです。
まず、モジュールの models
ディレクトリに不動産プロパティを表す単純なモデルを定義しましょう。
Odoo モデルは ir.model
レコードとしてデータベースに保存されます。他のレコードと同様に、XML ファイルで定義することができます:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="model_real_estate_property" model="ir.model">
<field name="name">Real Estate Property</field>
<field name="model">x_estate.property</field>
</record>
</odoo>
データファイルで定義されているすべてのモデルとフィールドの接頭辞は x_
でなければならないことに注意してください。 これは必須で、Pythonファイルで定義されているモデルやフィールドと区別するために使用されます。
Python で定義された古典的なモデルと同様に、Odoo は自動的に複数のフィールドをモデルに追加します。
id
(Id
) モデルのレコードに対する一意の識別子。create_date
(Datetime
) レコードの作成日時。create_uid
(Many2one
) レコードを作成したユーザ。write_date
(Datetime
) レコードの最終更新日。write_uid
(Many2one
) レコードを最後に更新したユーザ。
新しいモデルに複数のフィールドを追加することもできます。 名前(文字列)、値(float)、説明(html)、郵便番号(文字列)のような単純なフィールドを追加しましょう。
モデルと同様に、フィールドは単純に ir.model.fields
モデルのレコードであり、データファイルのように定義することができます。
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ...model definition from before... -->
<record id="field_real_estate_property_name" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_name</field>
<field name="field_description">Name</field>
<field name="ttype">char</field>
<field name="required">True</field>
</record>
<record id="field_real_estate_property_selling_price" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_selling_price</field>
<field name="field_description">Selling Price</field>
<field name="ttype">float</field>
<field name="required">True</field>
</record>
<record id="field_real_estate_property_description" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_description</field>
<field name="field_description">Description</field>
<field name="ttype">html</field>
</record>
<record id="field_real_estate_property_postcode" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_postcode</field>
<field name="field_description">Postcode</field>
<field name="ttype">char</field>
</record>
</odoo>
新しいフィールドには、さまざまな属性を設定できます。基本フィールドの場合は、次のようになります。
name
: フィールドの技術的な名前 (`x_`で始まる必要があります)field_description
: フィールドのラベルhelp
: インターフェイスに表示されるフィールドのヘルプテキストttype
: フィールドのタイプ (例:char
,integer
,float
,html
, など)required
: フィールドが必須かどうか(デフォルト:False
)readonly
: フィールドが読み取り専用かどうか(デフォルト:False
)index
: フィールドがインデックスされているかどうか (デフォルト:False
)copied
: レコードを複製するときにフィールドをコピーするかどうか(デフォルト:リレーショナルではない非計算フィールドの場合は`True`、リレーショナルおよび計算されたフィールドの場合は`False`)translate
: フィールドが翻訳可能かどうか (デフォルト:False
)
HTML のサニタイゼーションやその他のより高度な機能を制御するための属性も用意されています。完全なリストについては、 ir.model を参照してください。 :menuselection:`Settings --> Technical --> Database Structure --> Fields
メニューにあるデータベース内の ields` モデルまたは、 `ir. `base`モジュール内のodel.fields`モデル定義。
Exercise
次の基本フィールドをテーブルに追加します
フィールド |
型 |
必須 |
---|---|---|
x_date_availability |
日付 |
|
x_expected_price |
フロート |
True |
x_bedrooms |
整数 |
|
x_living_area |
整数 |
|
x_facades |
整数 |
|
x_garage |
Boolean |
|
x_garden |
Boolean |
|
x_garden_area |
整数 |
|
x_garden_orientation |
選択 |
x_garden_orientation
フィールドには、'North'、'South'、'East'、'West'の4つの値が必要です。 選択リストは、最初にフィールド自体の ir.model.fields
レコードを作成してから、 ir.model.fields.selection
レコードを作成する必要があります。 これらのレコードには、field_id
、`name`(UIの名前)、`value`(データベースの値)の3つのフィールドがあります。 `シーケンス`フィールドを設定することもできます は、選択項目が UI に表示される順序を制御します (下のシーケンス値が最初に表示されます)。
デフォルト値¶
Python では、フィールド宣言の default
引数を使用してフィールドにデフォルト値を設定できます。 データモジュールでは、デフォルト値は ir を作成することで設定されます。 各フィールドの efault
レコード。 例えば、以下のレコードを作成することで、すべてのプロパティに対して x_selling_price
フィールドのデフォルト値を 100000
に設定することができます。
<odoo>
<!-- ...model definition from before... -->
<record id="default_real_estate_property_selling_price" model="ir.default">
<field name="field_id" ref="estate.field_real_estate_property_selling_price" />
<field name="json_value">100000</field>
</record>
</odoo>
詳細は ir. を参照してください。 :menuselection:`Settings --> Technical --> Actions --> User-defined Defaults
メニューにあるデータベース内の efault` モデルまたは、 `ir. `base`モジュール内のefault`モデル定義。
警告
これらのデフォルトは静的ですが、ir.default
レコードの user_id
と company_id
フィールドを使用して、会社やユーザーによって設定できます。 例えば、x_date_availability
フィールドに対する動的なデフォルト値が "today" であることは不可能です。
セキュリティ¶
データモジュールのセキュリティはPythonモジュールとまったく同じで、 第4章:セキュリティー-簡単な紹介 にあります。
詳細はこのチュートリアルを参照してください。
ビュー¶
ビューは、ユーザーがデータとやり取りできるUIコンポーネントです。 これらは XML ファイルで定義されており、モジュールの views
ディレクトリにあります。
ビューとアクションは 第5章:最後に、いくつかのUIで遊べるもの と 第6章:基本ビュー で既に定義されているため、ここでは詳細を説明しません。
関連¶
Odooのようなリレーショナルシステムの本当の力は、レコードをリンクする能力にあります。 通常の Python モジュールでは、単一のコード行の他のモデルにリンクするために、モデル上の新しいフィールドを定義することができます。 データモジュールではまだ可能ですが、Pythonと同じ構文を使うことができないため、もう少しレグワークが必要です。
:doc:`server_framework_101/07_relations`のように、`estate`モジュールにいくつかリレーションを追加します。次のリンクを追加します:
その物件を購入した顧客
不動産を売却した不動産業者は
物件の種類:家、アパート、ペントハウス、お城...
物件を特徴づけるタグのリスト:居心地が良い、改装されている...
受け取ったオファーのリスト
Many-to-one¶
many-to-oneは別のオブジェクトへのシンプルなリンクです。例えば、``resへのリンクを定義するためです。 artner``ではモデルの新しいフィールドを定義できます
<odoo>
<!-- ...model definition from before... -->
<record id="field_real_estate_property_partner_id" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_partner_id</field>
<field name="field_description">Customer</field>
<field name="ttype">many2one</field>
<field name="relation">res.partner</field>
</record>
</odoo>
多対一のフィールドの場合、いくつかの属性をリレーションの詳細に設定できます。
relation
: リンクするモデルの名前 (必須)ondelete
: レコードが削除されたときに実行するアクション (デフォルト:set null
)domain
: リレーションに適用するドメインフィルタ
Exercise
以下のフィールドで新しいモデル
x_estate.property.type
を作成します。フィールド
型
必須
名前
文字
True
x_estate.property.type
モデルにアクションとリストビューとメニューアイテムを追加します。アクセス権をユーザーに与えるために
x_estate.property.type
モデルに追加します。x_estate.property
モデルに次のフィールドを作成します。フィールド
型
必須
x_property_type_id
Many2one (
x_estate.property.type
)True
x_partner_id
(buyer)Many2one (
res.partner
)x_user_id
(salesperson)Many2one (
res.users
)x_estate.property
モデルのフォームビューに新しいフィールドを含めます。
多対多で¶
多対多とは、オブジェクトのリストへのリレーションです。この例では、新しい``x_estateへの多対多のリレーションを定義します。 roperty.tag`` モデル。このタグはプロパティの特性を表します。例えば、改装、居心地の良い等です。
プロパティは多くのタグを持つことができ、タグは多くのプロパティに割り当てることができます - これは典型的な多対多の関係です。
多対多のフィールドは多対一のフィールドと同じ方法で定義されていますが、ttype`は`many2many`に設定されています。 `relation
属性は、リンクするモデルの名前にも設定されます。他の属性は、リレーションを制御するために設定できます。
relation_table
: リレーションに使用するテーブルの名前column1
とcolumn2
: リレーションに使用するカラムの名前
これらの属性はオプションであり、競合を避けるために2つのモデルの間に複数の多対多のフィールドがある場合にのみ指定する必要があります。 ほとんどの場合、Odoo ORMは使用する正しいリレーションテーブルと列を決定することができます。
Exercise
以下のフィールドで新しいモデル
x_estate.property.tag
を作成します。フィールド
型
必須
名前
文字
True
x_estate.property.tag
モデルにアクションとリストビューとメニューアイテムを追加します。ユーザーへのアクセスを許可するために
x_estate.property.tag
モデルにアクセス権を追加します。x_estate.property
モデルに次のフィールドを作成します。フィールド
型
x_property_tag_ids
Many2multi(
x_estate.property.tag
)x_estate.property
モデルのフォームビューに新しいフィールドを含めます。
1対多です¶
1対多のオブジェクトは、オブジェクトのリストへのリレーションです。この例では、新しい``x_estateへの1対多のリレーションを定義します。 roperty.offer`` モデル。このオファーは、顧客がプロパティを購入するために行ったオファーを表します。
1対多のフィールドは多対一のフィールドと同じ方法で定義されますが、ttype`は`one2many`に設定されています。 `relation
属性は、リンクするモデルの名前にも設定されます。リレーションを制御するためには、別の属性を設定する必要があります。
relation_field
: 親モデルへの参照を含む関連モデル上のフィールドの名前 (多対一のフィールド)。 これは二つのモデルをリンクするために使用されます。
Exercise
新しいモデル
x_estate.property.offer
を以下のフィールドで作成します。フィールド
型
必須
値
x_price
フロート
True
x_status
選択
承認、拒否
x_partner_id
Many2one (
res.partner
)True
x_property_id
Many2one (
x_estate.property
)True
ユーザーへのアクセスを許可するために
x_estate.property.offer
モデルにアクセス権を追加します。- 価格、partner_id、ステータスフィールドでツリービューとフォームビューを作成します。アクションやメニューを作成する必要はありません。
フィールド
x_offer_ids
をx_estate.property
モデルとフォームビューに追加します。
計算されたフィールド¶
計算されたフィールドは、Odoo のコア概念であり、他のフィールドに基づいて計算されるフィールドを定義するために使用されます。 これは、他のフィールドから派生したフィールドに便利です。 例えば、サブレコードの合計 (販売注文に含まれるすべての商品の価格を足します)。
参考: このトピックに関連するドキュメントは、 計算フィールド にあります。
データモジュールは、任意の型の計算フィールドを定義することができますが、Python モジュールと比較して非常に限られています。 実際、データモジュールは任意のコードを実行できないシステムにデプロイされることになっています。 許可されている Python コードは非常に限られています。
注釈
データモジュールのために書かれたすべての Python コードは、実行可能な操作を制限する Sandbox 環境で実行されます。 たとえば、ライブラリをインポートすることはできず、OSファイルにアクセスすることもできず、コンソールに印刷することもできません。 いくつかのユーティリティが提供されていますが、これは使用されるサンドボックス化された環境によって異なります。
計算方法の場合 サンドボックスは限られていてコードの実行を可能にする 最低限のユーティリティしか提供しない Python ビルドに加えて、 datetime
、 dateutil
、 time
モジュール (たとえば、日付の計算に役立つ) にもアクセスできます。
また、Sandbox で "dot assignation" が無効になっているため、計算方法で property.x_total_area = 1
を書くことはできません。 辞書アクセスを使用する必要があります: property['x_total_area'] = 1
. access フィールドのドット表記は正常に動作します: property.x_garden_area
は x_garden_area
フィールドの値を返します。
x_estate.property
モデルに 2 つの "area" フィールドを定義しました: living_area
と garden_area
。 2つの領域の合計を返すモデル上の計算フィールドを定義する データモジュールに次のコードを追加できます
<odoo>
<!-- ...model definition from before... -->
<record id="field_real_estate_property_total_area" model="ir.model.fields">
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="name">x_total_area</field>
<field name="field_description">Total Area</field>
<field name="ttype">float</field>
<field name="depends">x_living_area,x_garden_area</field>
<field name="compute"><![CDATA[
for property in self:
property['x_total_area'] = property.x_living_area + property.x_garden_area
]]>
</field>
</record>
</odoo>
注釈
サーバーのアクションでは、変数`records`を繰り返しますが、計算されたフィールドの場合 フィールドが計算されるレコードセットを含む self
変数を繰り返します。
depends
属性は、計算されたフィールドが依存するフィールドを定義するために使用され、(Python コードを使用して) フィールドを計算するために実行されるコードを定義するために compute
属性が使用されます。
Python モジュールとは異なり、計算されたフィールドはデフォルトで保存されます。計算されたフィールドを保存しないようにしたい場合(e. 、パフォーマンス上の理由やデータベースの膨張を避けるために)、store
属性を False
に設定できます。 同じことが readonly
にも適用されます: 計算フィールドを編集できないようにしたい場合は、readonly
属性を True
に設定する必要があります。
`CDATA`セクションはXMLではなく文字列であることをXMLパーサに指定するために使用されます。 これにより、パーサーは Python コードを XML として解釈したり、余分なスペースを追加したりすることができなくなります。 コードがデータベースに挿入されると、モジュールのインストール時刻になります。
Exercise
上に示すように、
x_living_area
とx_garden_area
フィールドの合計を返す計算フィールドをx_estate.property
モデルに追加します。x_estate.property
モデルのフォームビューにフィールドを含めます。
注釈
Python モジュールとは異なり、計算されたフィールドに対して逆または検索メソッドを定義することはできません。
コードとビジネス ロジック。¶
サーバーアクション¶
Pythonモジュールでは、モデル上の任意のメソッドを自由に定義できます。 一般的な使用パターンの1つは、いわゆる"actions"メソッドをモデルに追加し、これらのメソッドをUIのボタンにバインドすることです(e. を選択し、見積書を確認し、請求書を投稿するなどします。
In a data module, you can achieve the same effect by defining
Server Actions bound to your model. Server actions represent
pieces of logic that are run dynamically on the server. These actions can be configured manually
in the database directly via the
menu and can be of different
types; in our case, we will use the code
type which allows us to run any Python code in a
sandboxed environment.
この環境には、Odoo データベースとやり取りするのに役立つユーティリティがいくつか含まれています:
env
: レコードの環境model
: レコードのモデルuser
とuid
: 現在のユーザーと iddatetime
,dateutil
,timezone
,timezone
: 日付/時刻の計算に役立つライブラリfloat_compare
: 2 つのフロート値と与えられた精度を比較するユーティリティ関数b64encode
とb64decode
: base64 の値をエンコードおよびデコードするユーティリティ関数Command
: 複雑な式とコマンドを構築するのに役立つユーティリティクラス ( :ref:`ORMリファレンス <reference/fields/relational> `の`Command`クラスを参照)
加えて、 には、アクションが実行されるレコードセットへのアクセス権があります (通常はフォームビューからアクションが実行されると単一のレコードです)。 そして、アクションがリストビューから実行された場合に複数のレコードが record
と records
変数を介して実行されます。
注釈
アクションがクライアントにアクションを返す必要がある場合(例えば、ユーザーを別のビューにリダイレクトするなど) サーバーアクションのコード内の action
変数に割り当てることができます。 コードの Sandbox は実行後にコード内で定義された変数を検査し、action
変数の存在を検出すると自動的に返します。
website
モジュールがインストールされている場合 request
オブジェクトは、コードの Sandbox で使用できます。response
オブジェクトを response
変数に割り当てると、同様の方法でクライアントにレスポンスを返します。 これは、 :ref:の tutorials/importable_modules/website_controllers
セクションで詳しく説明されています。
例えば、x_estate.property
モデルでは、すべてのオファーの x_status
フィールドを Refused
に設定するアクションを定義できます。
<record id="action_x_estate_property_refuse_all_offers" model="ir.actions.server">
<field name="name">Refuse all offers</field>
<field name="model_id" ref="estate.model_real_estate_property"/>
<field name="state">code</field>
<field name="code"><![CDATA[
for property in records:
property.x_offer_ids.write({'x_status': 'refused'})
]]></field>
</record>
このアクションを x_estate のフォームビューにボタンとして含めること。 roperty
モデルでは、フォームビューのヘッダーに次の button ノードを追加できます。
<!-- form view definition from your code... -->
<header>
<button name="estate.action_x_estate_property_refuse_all_offers" type="action" string="Refuse all offers"/>
</header>
この操作を実行するためにギアアイコン()にエントリを追加することもできます。 をクリックして、既に混雑しているビューにボタンを追加しないようにします。 これを行うには、サーバーアクションをモデルや特定の種類のビューに*バインド*することができます。
<record id="action_x_estate_property_refuse_all_offers" model="ir.actions.server">
<field name="name">Refuse all offers</field>
<field name="model_id" ref="estate.model_real_estate_property"/>
<field name="state">code</field>
<field name="binding_model_id" ref="estate.model_real_estate_property"/>
<field name="binding_view_types">tree,form</field>
<field name="code"><![CDATA[
for property in records:
property.x_offer_ids.write({'x_status': 'refused'})
]]></field>
</record>
これにより、x_estateのギアアイコン(:icon:`fa-gear`)でアクションを利用できるようになります。 roperty
モデル、リスト内(チェックボックスを介して1つまたは複数のレコードが選択されている場合)とフォームビュー。
Exercise
x_estate.property にサーバーアクションを追加します。 オファーの ``x_status
フィールドをAccepted
に設定し、オファーがそれに応じてアタッチされるプロパティの販売価格と購入者を更新するffer`` モデル。 このアクションはRefused
と同じプロパティにある他のすべてのオファーをマークする必要があります。この操作を実行できるオファーのリストビューにボタンを含める
Pythonモデルをオーバーライド¶
UI 要素経由で¶
Python モジュールとは異なり、Python モデルのメソッドをきれいにオーバーライドすることはできません。
ただし、 場合によっては、これらのメソッドを呼び出すUIの要素を置き換え、サーバーアクション内でこれらのメソッドへの呼び出しを傍受することが可能です。
典型的な例として、Odoo の Sales
アプリとの統合が挙げられます。 特定の製品が販売されるときに、不動産モジュールが販売アプリケーションと統合されていることを想像してみましょう(e. 、プロパティの販売を管理するための見積もり)、自動的にあなたのモジュールに新しいプロパティレコードを作成したいです。
これを達成するには、次のことが必要です:
ボタンの元のメソッドを呼び出し、メソッド呼び出しの前後にカスタムロジックを追加するサーバーアクションを作成します
ビュー内のボタンをサーバーアクションを呼び出すカスタムボタンで置き換えます
<record id="view_sale_order_form" model="ir.ui.view">
<field name="name">sale.order.form.inherit.estate</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<xpath expr="//button[@name='action_confirm'][@type='object']" position="attributes">
<attribute name="type">action</attribute>
<attribute name="name">estate.action_x_estate_property_create_from_sale_order</attribute>
</xpath>
<!-- since the button is present twice in the original view, we need to replace it twice -->
<xpath expr="//button[@name='action_confirm'][@type='object']" position="attributes">
<attribute name="type">action</attribute>
<attribute name="name">estate.action_x_estate_property_create_from_sale_order</attribute>
</xpath>
</field>
</record>
<record id="action_x_estate_property_create_from_sale_order" model="ir.actions.server">
<field name="name">Confirm and create property from sale order</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="state">code</field>
<field name="code"><![CDATA[
for order in records:
order.action_confirm()
property_type = env['x_estate.property.type'].sudo().search([('x_name', '=', 'Other')], limit=1)
property = env['x_estate.property'].sudo().create({
'x_name': order.name,
'x_expected_price': 0,
'x_selling_price': 0,
'x_sale_order_id': order.id,
'x_property_type_id': property_type.id,
})
]]></field>
</record>
自動化ルールによる¶
自動化ルールは、特定のトリガーに基づいてデータベース内のレコードに対して自動的にアクションを実行する方法です。 国家の変更やタグの追加などです 例えば、オファーが承認されたときにメールを送信するなどして、レコードのライフサイクルイベントに行動を結び付けるのに役立ちます。
オートメーションルールを使用して標準動作を拡張することは、UIベースのアプローチよりも堅牢になります。これは、ライフサイクルイベントがボタン経由で発生した場合にも実行されるためです(例えば。 Webhookまたはメソッドへの直接呼び出しを介して; 例えば、見積もりがポータルや電子商取引を介して確認された場合)。 しかし、彼らは適切に設定するにはもう少し細かいです。 自動化を確実に実行する必要があります特定のフィールドを監視するなどによって 適切な時期にのみ実行されます
ドキュメント: このトピックに関連するより完全なドキュメントは、 自動化規則 にあります。
注釈
自動化ルールは base
モジュールの一部ではありません。base_automation
モジュールが付属しています。 データモジュールでオートメーションルールを定義する場合は、base_automation
がモジュールの依存関係の一部であることを確認する必要があります。
インストールすると、オートメーションルールは
メニューから管理されます。自動化ルールは、データモジュールと既存の標準的なOdooモジュールを結び付ける場合に特に便利です。 データモジュールはメソッドをオーバーライドできないため、自動化を標準モデルのライフサイクル変更と結び付けることは、標準モジュールを拡張する一般的な方法です。
オートメーションルールを使用して前のセクションから例を書き直す場合、いくつかの変更が必要になります。
サーバーアクションはボタンの元のメソッドを呼び出さないでください (代わりに、ボタンの元のメソッドを呼び出してください)。 最初の方法で自動化ルールを解除する変更が起動します)
ビュー拡張機能は必要ありません
適切なイベントでサーバーアクションをトリガーするために自動化ルールを定義する必要があります
<record id="action_x_estate_property_create_from_sale_order" model="ir.actions.server">
<field name="name">Create property from sale order</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="state">code</field>
<field name="code"><![CDATA[
for order in records:
property_type = env['x_estate.property.type'].sudo().search([('x_name', '=', 'Other')], limit=1)
property = env['x_estate.property'].sudo().create({
'x_name': order.name,
'x_expected_price': 0,
'x_selling_price': 0,
'x_sale_order_id': order.id,
'x_property_type_id': property_type.id,
})
]]></field>
</record>
<record id="automation_rule_x_estate_property_create_from_sale_order" model="base.automation">
<field name="name">Create property from sale order</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="trigger">on_state_set</field>
<field name="trg_selection_field_id" ref="sale.selection__sale_order__state__sale"/>
<field name="trigger_field_ids" eval="[(4, ref('sale.field_sale_order__state'))]"/>
<field name="action_server_ids" eval="[(4, ref('estate.action_x_estate_property_create_from_sale_order'))]"/>
</record>
XML ID から標準の Odoo モデル、フィールド、選択値などに注意してください。 Odoo インスタンス自体には、テクニカルメニュー内の適切なレコードに移動し、デバッグメニューの View Metadata
メニューエントリを使用しています。 モデルの XML ID は単にモデル名で、アンダースコアに置き換えられ、 model_
(e. 、sale.model_sale_order
は sales
です。 sale
モジュールで定義されている rder`` ); フィールドの XML ID は、モデル名にアンダースコアに置き換えられ、モデル名とフィールド名 (e. 、sale.field_sale_order__name
は、 sale.order
モデルの name
フィールドの XML ID です。
ウェブサイトコントローラ¶
Odoo の HTTP コントローラは通常、モジュールの controllers
ディレクトリで定義されます。 データモジュールでは、ウェブサイトモジュールがインストールされている場合、コントローラとして動作するサーバアクションを定義することができます。
ウェブサイトモジュールがインストールされているとき サーバアクションは ウェブサイトで利用可能
としてマークし、パスを与えることができます(URLの衝突を避けるために、フルパスは /website/action
の前に常に追加されます) グローバルの request
オブジェクトは、コードサーバーアクションのローカルスコープで利用可能になります。
request
オブジェクトは、リクエストの本文にアクセスするためのいくつかのメソッドを提供します。
request.get_http_params()
: クエリ文字列と本文に存在するフォームからキーと値のペアを抽出します(application/x-www-form-urlencoded
とmultipart/form-data
の両方)。request.get_json_data()
: リクエストの本文からJSONデータを抽出します。
サーバーアクション内から値を返すことはできないため、リターンへの応答を定義することができます。 response-like object を response
変数に割り当てると、自動的にウェブサイトに戻ります。
URL /website/action/estate
が呼び出されたときにプロパティのリストを返すシンプルなウェブサイトコントローラの例を以下に示します。
<record id="server_action_estate_list" model="ir.actions.server">
<field name="name">Estate List Controller</field>
<field name="model_id" ref="estate.model_real_estate_property" />
<field name="website_published">True</field>
<field name="website_path">estate</field>
<field name="state">code</field>
<field name="code"><![CDATA[
html = '<html><body><h1>Properties</h1><ul>'
for property in request.env['x_estate.property'].search([]):
html += f'<li>{property.x_name}</li>'
html += '</ul></body></html>'
response = request.make_response(html)
]]></field>
</record>
request
オブジェクトには、レスポンスオブジェクトの生成を促進するためにいくつかの便利なメソッドがあります。
request.render(template, qcontext=None, lazy=True, **kw)
は xmlid を使用してQWeb テンプレートをレンダリングします。追加のキーワード引数は `werkzeugに転送されます。 esponse`オブジェクト (例えば、クッキー、ヘッダーなど)request. 別の URL にリダイレクトする場合は edirect(location, code=303, local=True)
を使用します;local
引数を使用して、リダイレクトをウェブサイトからの相対位置にするかどうかを指定します(デフォルトはTrue
)。`request.notfound()`は`werkzeug.HTTPException`例外を返し、ウェブサイトに404エラーを通知します。
`request.make_response(data, headers=None, cookies=None, status=200)`を手動で`werkzeug.Response`オブジェクトを作成します。`status`引数は返すHTTPステータスコードです(デフォルト: 200)。
request.make_json_response(data, headers=None, cookies=None, status=200)
は JSON レスポンスを手動で作成します。データは `json を使用して json-serialized になります。 umps`ユーティリティ; これは、API呼び出しを介してサーバー間の通信を設定するのに便利です。
実装の詳細やその他(一般的ではない)メソッドについては、`odoo.http`モジュール内の`Request`オブジェクトの実装を参照してください。
セキュリティ上の懸念は開発者に委ねられていることに注意してください (通常はセキュリティルールを通して、またはレコードにアクセスするには sudo
を使用しています)。
注釈
サーバーアクションの model_id
フィールドで使用されるモデルは、このサーバーアクションを実行するための書き込み操作を公開ユーザーがアクセスできる必要があります。 さもなければサーバーアクションは403エラーを返します。 アクセスを避ける方法は、公開ユーザがアクセス可能なモデルにサーバーアクションをリンクすることです。 典型的な例は `ir. にサーバーのアクションをリンクすることです。 ilters`モデル
Exercise
JSON APIをモジュールに追加して、外部サービスが販売のためのプロパティのリストを取得できるようにします。
モデルに
x_api_published
フィールドを追加し、プロパティをAPI上で公開するかどうかを制御します。公開ユーザがモデルを読み書きできるようにアクセス権レコードを追加します
不可能なドメインを持つ書き込み操作のレコードルールを追加することで、公開ユーザーからの書き込みを防ぎます(例:
[('id', '=', False)]
)x_api_published
としてマークされたプロパティが公開ユーザーによって読み取れるようにレコードルールを追加します。URL `/website/action/estate`が呼び出された場合、JSON形式でプロパティのリストを返すサーバーアクションを追加します
JavaScriptの<unk>¶
インポート可能なモジュールにはPythonファイルを含めることはできませんが、JavaScriptファイルにそのような制限は存在しません。 JavaScriptファイルをインポート可能なモジュールに追加するのは、標準のOdooモジュールに追加するのとまったく同じです。
これは、インポート可能なモジュールが新しいフィールドコンポーネントやまったく新しいビューを含めることができることを意味します。
例として、簡単なツアーをEstate モジュールに追加しましょう。 ツアーはOdooの標準的なメカニズムであり、アプリケーションを通してユーザーを案内することによってオンボードユーザーに使用されます。
`static/src/js/tour.js`にこのファイルを追加することで、単一のステップを持つ非常に最小限のツアーを追加できます。
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add('estate_tour', {
url: "/web",
steps: () => [{
trigger: '.o_app[data-menu-xmlid="estate.menu_root"]',
content: 'Start selling your properties from this app!',
}],
});
次に、マニフェストファイルに適切なバンドルにファイルを含める必要があります。
{
"name": "Real Estate",
# [...]
"assets": {
"web.assets_backend": [
"estate/static/src/js/tour.js",
],
},
}
ツアーが表示されるように、データ フォルダー内の新しい estate_tour.xml ファイルに xml レコードを追加する必要があります。
<record id="estate_tour" model="web_tour.tour">
<field name="name">estate_tour</field>
<field name="sequence">2</field>
<field name="rainbow_man_message">Welcome! Happy exploring.</field>
</record>
注釈
通常のPythonモジュールとは異なり、glob展開はインポート可能なモジュールではサポートされていません。 モジュールに含めたいファイルをリストする必要があります