第12章:継承¶
Odooの強力な側面は、そのモジュール性です。モジュールはビジネスニーズに特化していますが、モジュール同士で相互に作用することもできます。これは、既存のモジュールの機能を拡張するのに便利です。例えば、不動産のシナリオでは、営業担当者の物件リストを通常のユーザービューに直接表示させたいとします。
ですが、具体的なOdooモジュールの継承を行う前に、標準的なCRUD (Create, Retrieve, Update or Delete) メソッドの動作をどのように変更できるかを見てみましょう。
Pythonでの継承¶
注釈
目標: このセクションの最後には、
新規またはキャンセルされていないプロパティを削除することはできません。

オファーが作成されると、物件の状態が
Offer Received
に変更されるようになります。既存のオファーよりも低い価格のオファーを作成することはできなくなります。

不動産モジュールでは、標準的なCRUDアクションを行うために特別なものを開発する必要はありませんでした。Odooのフレームワークはそれらを行うために必要なツールを提供します。実際、そのようなアクションは、標準的なPythonでの継承のおかげで、このモデルにすでに含まれています。
from odoo import fields, models
class TestModel(models.Model):
_name = "test_model"
_description = "Test Model"
...
class TestModel
は Model
を継承しています。これは create()
、 read()
、 write()
と unlink()
を提供します。
これらのメソッド(および Model
で定義されている他のメソッド)は、特定のビジネスロジックを追加するために拡張することができます:
from odoo import fields, models
class TestModel(models.Model):
_name = "test_model"
_description = "Test Model"
...
@api.model
def create(self, vals):
# Do some business logic, modify vals...
...
# Then call super to execute the parent method
return super().create(vals)
デコレーターの model()
は、 create()
メソッドに必要です。 レコードセットの self
の内容は、作成のコンテキストでは関連性がないからです。 しかし、他のCRUDのメソッドには必要ありません。
It is also important to note that even though we can directly override the
unlink()
method, you will almost always want to write a new method with
the decorator ondelete()
instead. Methods marked with this decorator will be
called during unlink()
and avoids some issues that can occur during
uninstalling the model's module when unlink()
is directly overridden.
Python 3 では super()
は super(TestModel, self)
と同等です。 後者は、変更されたレコードセットを使用して親メソッドを呼び出す場合に、必要になるかもしれません。
危険
フローを壊さないように、 常に
super()
を呼び出すことは非常に重要です。super()
を呼び出したくない場合は、非常に特殊なケースに限られます。常に 親メソッドと一致したデータを返すようにしてください。例えば、親メソッドが
dict()
を返す場合、オーバーライドしたメソッドもdict()
を返さなければなりません。
Exercise
CRUD メソッドにビジネス・ロジックを追加してみましょう。
状態が「新規」または「キャンセル」でない場合、プロパティの削除を防止します
ヒント: ondelete()
デコレータで新しいメソッドを作成し、self
は複数のレコードを持つレコードセットにすることができます。
オファーの作成時に、物件情報の状態を
Offer Received
に設定します。また、ユーザが既存のオファーよりも低い金額のオファーを作成しようとすると、エラーを発生させるようにします。
ヒント: property_id
フィールドは vals
で利用できますが、 int
型です。 estate.property
オブジェクトをインスタンス化するには、 self.env[model_name].browse(value)
(例) を使用します。
モデルの継承¶
参考: このトピックに関連する文書は 継承と拡張 にあります。
不動産モジュールでは、営業担当者にリンクされた物件のリストを、設定/ユーザーと会社/ユーザーのフォームビューに直接表示したいと考えています。そのためには、 res.users
モデルにフィールドを追加し、それを表示するようにビューを変更する必要があります。
Odoo は 2 つの 継承 メカニズムを提供し、モジュラー方法で既存のモデルを拡張します。
1つ目の継承メカニズムでは、他のモジュールで定義されたモデルの動作を、次の手順で変更することができます。
モデルにフィールドを追加し、
モデル内のフィールドの定義をオーバーライドし、
モデルに制約を加え、
モデルにメソッドを追加し、
モデルの既存のメソッドをオーバーライドする。
2つ目の継承メカニズム (デリゲーション) は、モデルのすべてのレコードが親モデルのレコードにリンクされ、この親レコードのフィールドへの透過的なアクセスを可能にします。

Odooでは、1つ目のメカニズムが最もよく使われています。今回のケースでは、既存のモデルにフィールドを追加したいので、1つ目のメカニズムを使用することになります。例えば、次のようになります。
from odoo import fields, models
class InheritedModel(models.Model):
_inherit = "inherited.model"
new_field = fields.Char(string="New Field")
モデルに2つのフィールドを追加する実用的な例は こちら です。
慣例的に、継承されたモデルはそれぞれのPythonファイルで定義されます。この例では、 models/inherited_model.py
となります。
Exercise
Users にフィールドを追加してみましょう。
次のフィールドを
res.users
に追加します。
フィールド |
型 |
---|---|
プロパティ id |
|
このフィールドにドメインを追加して、利用可能な物件情報のみをリストアップするようにします。
次のセクションでは、ビューにフィールドを追加し、すべてが正常に動作していることを確認しましょう!
ビューの継承¶
参照: このトピックに関連するドキュメントは、 :ref:`reference/view_records/inherited from にあります。
注釈
目標: このセクションの最後には、営業担当者にリンクされた利用可能な物件情報のリストが、そのユーザーフォームのビューに表示されるようになっています。

Odooでは、既存のビューをそのまま変更する (上書きする) のではなく、ルートビューのトップに子の 拡張
ビューを適用できるといった、ビューの継承を提供しています。この拡張ビューは、親ビューにコンテンツを追加・削除することができます。
拡張ビューは inherit_id
フィールドを使用して親を参照します。単一のビューの代わりに、 arch
フィールドには、親ビューのコンテンツを選択・変更する複数の xpath
要素を含むようにします。
<record id="inherited_model_view_form" model="ir.ui.view">
<field name="name">inherited.model.form.inherit.test</field>
<field name="model">inherited.model</field>
<field name="inherit_id" ref="inherited.inherited_model_view_form"/>
<field name="arch" type="xml">
<!-- find field description and add the field
new_field after it -->
<xpath expr="//field[@name='description']" position="after">
<field name="new_field"/>
</xpath>
</field>
</record>
expr
親ビューで単一の要素を選択している XPath 式。要素がない、または複数の要素に一致する場合にエラーが発生します。
position
マッチした要素に適用する操作:
inside
マッチした要素の末尾に
xpath
のボディを追加します。replace
マッチした要素を
xpath
のボディーに置き換え、新しいボディの$0
ノードの発生を元の要素に置き換えます。before
一致する要素の前に
xpath
の本体を兄弟として挿入します。after
一致する要素の後に
xpaths
の本体を兄弟として挿入します。attributes
xpath
のbodyで指定されたattribute
要素を使って、マッチした要素の属性を変更します。
単一の要素にマッチする場合、 position
属性を検索対象の要素に直接設定することができます。次のどちらの継承も同じ結果になります。
<xpath expr="//field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
ビュー継承拡張の例は こちら にあります。
Exercise
Usersビューにフィールドを追加してみましょう。
新しいノートブックページの base.view_users_form
に property_ids
フィールドを追加します。
ヒント: ユーザービューの継承例は こちら です。
Odooではモジュラーコンセプトのため、継承が広く使われています。詳細については、対応するドキュメントをお読みください。
:doc:`next chapter <13_other_module>`では、他のモジュールとやり取りする方法を学びます。