Chapter 12: Inheritance

Потужним аспектом Odoo є його модульність. Модуль призначений для потреб бізнесу, але модулі також можуть взаємодіяти один з одним. Це корисно для розширення функціональності існуючого модуля. Наприклад, у нашому сценарії нерухомості ми хочемо відобразити список властивостей продавця безпосередньо в представленні звичайного користувача.

Але перед тим, як перейти до конкретного успадкування модуля Odoo, давайте подивимося, як ми можемо змінити поведінку стандартних методів CRUD (Створення, Отримання, Оновлення або Видалення).

Спадкування Python

Примітка

Ціль: у кінці цього розділу:

  • Не повинно бути можливо видалити властивість, яка не є новою або скасованою.

Від’єднати
  • Після створення пропозиції стан властивості має змінитися на „Пропозицію отримано“

  • Не повинно бути можливості створити пропозицію з нижчою ціною, ніж існуюча пропозиція

Cтворити

У нашому модулі нерухомості нам ніколи не доводилося розробляти щось конкретне, щоб мати змогу виконувати стандартні дії 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 зворотне до поля, яке посилається на продавця в estate.property

  • Додайте домен у поле, щоб у ньому відображалися лише доступні властивості.

У наступному розділі давайте додамо поле до перегляду та перевіримо, чи все працює добре!

Переглянути успадкування

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.