Розділ 4: Моделі та базові поля

Наприкінці попереднього розділу ми змогли створити модуль Odoo. Однак на даний момент це все ще порожня оболонка, яка не дозволяє нам зберігати жодні дані. У нашому модулі нерухомості ми хочемо зберігати інформацію, пов’язану з нерухомістю (назва, опис, ціна, житлова площа…) у базі даних. Фреймворк Odoo надає інструменти для полегшення взаємодії з базами даних.

Перш ніж рухатися вперед у вправі, переконайтеся, що модуль estate встановлено, тобто він має відображатися як „Встановлено“ у списку додатків.

Попередження

Не використовуйте змінні глобальні змінні.

Один екземпляр Odoo може запускати кілька баз даних паралельно в одному процесі python. У кожній із цих баз даних можуть бути встановлені різні модулі, тому ми не можемо покладатися на глобальні змінні, які оновлюватимуться залежно від встановлених модулів.

Об’єктно-реляційне відображення

Довідка: документацію, пов’язану з цією темою, можна знайти в Моделі API.

Примітка

Мета: у кінці цього розділу має бути створена таблиця estate_property:

$ psql -d rd-demo
rd-demo=# SELECT COUNT(*) FROM estate_property;
count
-------
    0
(1 row)

Ключовим компонентом Odoo є рівень ORM. Цей рівень дозволяє уникнути необхідності вручну писати більшість SQL і забезпечує розширюваність і служби безпеки2.

Бізнес-об’єкти оголошуються як класи Python, що розширюють Model, який інтегрує їх в автоматизовану систему збереження.

Моделі можна налаштувати, встановивши ряд атрибутів при їх визначенні. Найважливішим атрибутом є _name, який є обов’язковим і визначає назву моделі в системі Odoo. Ось мінімально повне визначення моделі:

from odoo import models

class TestModel(models.Model):
    _name = "test_model"

Цього визначення достатньо, щоб ORM створив таблицю бази даних під назвою test_model. За домовленістю всі моделі розташовані в каталозі models, і кожна модель визначається у власному файлі Python.

Подивіться, як визначається таблиця crm_recurring_plan і як імпортується відповідний файл Python:

  1. Модель визначається у файлі crm/models/crm_recurring_plan.py (див. тут)

  2. Файл crm_recurring_plan.py імпортується в crm/models/__init__.py (див. тут)

  3. Папка models імпортується в crm/__init__.py (див. тут)

Exercise

Визначте модель властивостей нерухомості.

На основі прикладу, наведеного в модулі CRM, створіть відповідні файли та папку для таблиці estate_property.

Після створення файлів додайте мінімальне визначення для моделі estate.property.

Будь-яка зміна файлів Python вимагає перезапуску сервера Odoo. Коли ми перезапустимо сервер, ми додамо параметри -d і -u:

$ ./odoo-bin --addons-path=addons,../enterprise/,../technical-training-sandbox/ -d rd-demo -u estate

-u estate означає, що ми хочемо оновити модуль estate, тобто ORM застосує зміни схеми бази даних. У цьому випадку створюється нова таблиця. -d rd-demo означає, що оновлення має бути виконано в базі даних rd-demo. -u завжди слід використовувати в комбінації з -d.

Під час запуску ви повинні побачити такі попередження:

...
WARNING rd-demo odoo.models: The model estate.property has no _description
...
WARNING rd-demo odoo.modules.loading: The model estate.property has no access rules, consider adding one...
...

Якщо це так, то вам має бути добре! Щоб переконатися, двічі перевірте за допомогою psql, як показано в Ціль.

Exercise

Додати опис.

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

Поле моделі

Довідка: документацію, пов’язану з цією темою, можна знайти в Моделі API.

Поля використовуються для визначення того, що може зберігати модель і де вони зберігаються. Поля визначаються як атрибути в класі моделі:

from odoo import fields, models

class TestModel(models.Model):
    _name = "test_model"
    _description = "Test Model"

    name = fields.Char()

Поле name є Char, яке буде представлено як str Python Unicode і VARCHAR SQL.

Типи

Примітка

Ціль: наприкінці цього розділу до таблиці estate_property слід додати кілька основних полів:

$ psql -d rd-demo

rd-demo=# \d estate_property;
                                            Table "public.estate_property"
    Column       |            Type             | Collation | Nullable |                   Default
--------------------+-----------------------------+-----------+----------+---------------------------------------------
id                 | integer                     |           | not null | nextval('estate_property_id_seq'::regclass)
create_uid         | integer                     |           |          |
create_date        | timestamp without time zone |           |          |
write_uid          | integer                     |           |          |
write_date         | timestamp without time zone |           |          |
name               | character varying           |           |          |
description        | text                        |           |          |
postcode           | character varying           |           |          |
date_availability  | date                        |           |          |
expected_price     | double precision            |           |          |
selling_price      | double precision            |           |          |
bedrooms           | integer                     |           |          |
living_area        | integer                     |           |          |
facades            | integer                     |           |          |
garage             | boolean                     |           |          |
garden             | boolean                     |           |          |
garden_area        | integer                     |           |          |
garden_orientation | character varying           |           |          |
Indexes:
    "estate_property_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "estate_property_create_uid_fkey" FOREIGN KEY (create_uid) REFERENCES res_users(id) ON DELETE SET NULL
    "estate_property_write_uid_fkey" FOREIGN KEY (write_uid) REFERENCES res_users(id) ON DELETE SET NULL

Існує дві широкі категорії полів: „прості“ поля, які є атомарними значеннями, що зберігаються безпосередньо в таблиці моделі, і „реляційні“ поля, які пов’язують записи (одних і тих самих або різних моделей).

Прості приклади полів Boolean, Float, Char, Text, Date і Selection.

Exercise

Додайте основні поля до таблиці Нерухомість.

Додайте в таблицю такі основні поля:

Поле

Тип

name

Char

description

Text

postcode

Char

date_availability

Дата

expected_price

Float

selling_price

Float

bedrooms

Integer

living_area

Integer

facades

Integer

garage

Boolean

garden

Boolean

garden_area

Integer

garden_orientation

Selection

Поле garden_orientation повинно мати 4 можливі значення: „Північ“, „Південь“, „Схід“ і „Захід“. Список вибору визначається як список кортежів, приклад див. тут.

Коли поля додано до моделі, перезапустіть сервер за допомогою -u estate

$ ./odoo-bin --addons-path=addons,../enterprise/,../technical-training-sandbox/ -d rd-demo -u estate

Підключіться до psql і перевірте структуру таблиці estate_property. Ви помітите, що до таблиці також додано кілька додаткових полів. Ми переглянемо їх пізніше.

Загальні атрибути

Примітка

Ціль: у кінці цього розділу стовпці name і expected_price не повинні мати значення null в таблиці estate_property:

rd-demo=# \d estate_property;
                                            Table "public.estate_property"
    Column       |            Type             | Collation | Nullable |                   Default
--------------------+-----------------------------+-----------+----------+---------------------------------------------
...
name               | character varying           |           | not null |
...
expected_price     | double precision            |           | not null |
...

Подібно до самої моделі, її поля можна налаштувати, передавши атрибути конфігурації як параметри:

name = fields.Char(required=True)

Деякі атрибути доступні для всіх полів, ось найпоширеніші:

string (unicode, за умовчанням: назва поля)

Мітка поля в інтерфейсі користувача (видима користувачами).

required (bool, за умовчанням: False)

Якщо True, поле не може бути порожнім, воно повинно або мати значення за замовчуванням, або завжди мати значення під час створення запису.

help (str, за умовчанням: '')

Надає розширену довідкову підказку для користувачів в інтерфейсі користувача.

index (bool, за умовчанням: False)

Запитує, щоб Odoo створив індекс бази даних для стовпця.

Exercise

Встановити атрибути для існуючих полів.

Додайте такі атрибути:

Поле

Атрибут

name

обов’язкові

expected_price

обов’язкові

Після перезапуску сервера обидва поля не повинні мати значення NULL.

Автоматичні поля

Посилання: документацію щодо цієї теми можна знайти в Автоматичні поля.

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

id (Id)

Унікальний ідентифікатор для запису моделі.

create_date (Datetime)

Дата створення запису.

create_uid (Many2one)

Користувач, який створив запис.

write_date (Datetime)

Дата останньої зміни запису.

write_uid (Many2one)

Користувач, який останній змінював запис.

Тепер, коли ми створили нашу першу модель, давайте додамо трохи безпеки!

1

можна вимкнути автоматичне створення деяких полів

2

написання необроблених запитів SQL можливе, але вимагає обережності, оскільки воно обходить усі механізми автентифікації та безпеки Odoo.