Chapter 12: Inheritance¶
Потужним аспектом Odoo є його модульність. Модуль призначений для потреб бізнесу, але модулі також можуть взаємодіяти один з одним. Це корисно для розширення функціональності існуючого модуля. Наприклад, у нашому сценарії нерухомості ми хочемо відобразити список властивостей продавця безпосередньо в представленні звичайного користувача.
Але перед тим, як перейти до конкретного успадкування модуля Odoo, давайте подивимося, як ми можемо змінити поведінку стандартних методів CRUD (Створення, Отримання, Оновлення або Видалення).
Спадкування Python¶
Примітка
Ціль: у кінці цього розділу:
Не повинно бути можливо видалити властивість, яка не є новою або скасованою.

Після створення пропозиції стан властивості має змінитися на „Пропозицію отримано“
Не повинно бути можливості створити пропозицію з нижчою ціною, ніж існуюча пропозиція

У нашому модулі нерухомості нам ніколи не доводилося розробляти щось конкретне, щоб мати змогу виконувати стандартні дії 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()
, щоб уникнути порушення потоку. Є лише кілька дуже конкретних випадків, коли ви не хочете це називати.Обов’язково завжди повертайте дані, які відповідають батьківському методу. Наприклад, якщо батьківський метод повертає
dict()
, ваше перевизначення також має повертатиdict()
.
Exercise
Додайте бізнес-логіку до методів CRUD.
Запобігання видаленню властивості, якщо її стан не „Новий“ або „Скасовано“
Tip: create a new method with the ondelete()
decorator and remember that
self
can be a recordset with more than one record.
Під час створення пропозиції встановіть стан властивості „Пропозицію отримано“. Також виникає помилка, якщо користувач намагається створити пропозицію з меншою сумою, ніж існуюча пропозиція.
Порада: поле property_id
доступне в vals
, але це int
. Щоб створити екземпляр об’єкта estate.property
, використовуйте self.env[model_name].browse(value)
(приклад)
Модель спадкування¶
Посилання: документацію щодо цієї теми можна знайти в Пошук доменів.
У нашому модулі нерухомості ми хотіли б відобразити список властивостей, пов’язаних із продавцем, безпосередньо в режимі представлення форми Налаштування / Користувачі та компанії / Користувачі. Для цього нам потрібно додати поле до моделі res.users
і адаптувати його вигляд, щоб його відображати.
Odoo надає два механізми успадкування для розширення існуючої моделі модульним способом.
Перший механізм успадкування дозволяє модулям змінювати поведінку моделі, визначеної в іншому модулі, шляхом:
додавання полів до моделі,
заміна визначення полів у моделі,
додавання обмежень до моделі,
додавання методів до моделі,
перевизначаючи існуючі методи в моделі.
Другий механізм успадкування (делегування) дозволяє кожному запису моделі бути пов’язаним із записом батьківської моделі та забезпечує прозорий доступ до полів цього батьківського запису.

В Odoo перший механізм є найбільш використовуваним. У нашому випадку ми хочемо додати поле до існуючої моделі, що означає, що ми будемо використовувати перший механізм. Наприклад:
from odoo import fields, models
class InheritedModel(models.Model):
_inherit = "inherited.model"
new_field = fields.Char(string="New Field")
Практичний приклад додавання двох полів до моделі можна знайти тут.
За домовленістю кожна успадкована модель визначається у власному файлі Python. У нашому прикладі це буде models/inherited_model.py
.
Exercise
Додайте поле до Користувачів.
Додайте наступне поле до
res.users
:
Поле |
Тип |
---|---|
property_ids |
One2many зворотне до поля, яке посилається на продавця в |
Додайте домен у поле, щоб у ньому відображалися лише доступні властивості.
У наступному розділі давайте додамо поле до перегляду та перевіримо, чи все працює добре!
Переглянути успадкування¶
Reference: the documentation related to this topic can be found in Спадкування.
Примітка
Ціль: наприкінці цього розділу список доступних властивостей, пов’язаних із продавцем, має відображатися у представленні форми користувача

Замість того, щоб змінювати існуючі представлення на місці (шляхом їх перезапису), 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
змінює атрибути відповідного елемента за допомогою спеціальних елементів
attribute
в тіліxpath
При зіставленні одного елемента атрибут position
можна встановити безпосередньо для елемента, який потрібно знайти. Обидва успадкування нижче мають однаковий результат.
<xpath expr="//field[@name='description']" position="after">
<field name="idea_ids" />
</xpath>
<field name="description" position="after">
<field name="idea_ids" />
</field>
Приклад розширення успадкування представлення можна знайти тут <https://github.com/odoo/odoo/blob/691d1f087040f1ec7066e485d19ce3662dfc6501/addons/account_fleet/views/account_move_views.xml#L3-L17>`__.
Exercise
Додайте поля до представлення користувачів.
Додайте поле property_ids
до base.view_users_form
на новій сторінці notebook.
Порада: приклад успадкування представлення користувача можна знайти тут <https://github.com/odoo/odoo/blob/691d1f087040f1ec7066e485d19ce3662dfc6501/addons/gamification/views/res_users_views.xml#L5-L14>`__.
Успадкування широко використовується в Odoo завдяки його модульній концепції. Не соромтеся прочитати відповідну документацію для отримання додаткової інформації!
In the next chapter, we will learn how to interact with other modules.