Перейти к содержимому

Наследуемые поля в Odoo: как ORM передаёт данные между моделями

Практическое руководство по тому, как работает наследование полей в Odoo и как эффективно применять его при разработке собственных модификаций
6 марта 2026 г. от
Наследуемые поля в Odoo: как ORM передаёт данные между моделями
Dasolo
| Комментариев пока нет

Введение


При работе с разработкой Odoo вы постоянно будете сталкиваться с понятием наследования. В ядре ORM Odoo заложена идея повторного использования структуры и поведения моделей: вместо копирования кода и данных модель может «подхватить» поля и методы другой модели, сохраняя целостность данных и снижая дублирование.


Унаследованные поля — ключевой инструмент этой системы. Они позволяют одной модели обращаться к полям, физически хранящимся в другой модели, так будто эти поля принадлежат первой. Освоив этот принцип, вы начнёте лучше понимать поведение большинства стандартных связей в Odoo.


В этой статье мы разберём, что такое унаследованные поля, какие есть типы наследования в Odoo, как данные хранятся в базе и как использовать эти механизмы в реальных кастомизациях.

Что такое унаследованное поле в Odoo?


В контексте ORM Odoo поле считается унаследованным, когда одна модель получает доступ к полю, определённому в другой модели, с помощью одного из механизмов наследования. Вместо создания нового поля вручную модель-потомок переиспользует уже существующее.


Это одна из причин, почему модель данных Odoo остаётся компактной: одно и то же поле, например имя клиента, может показываться в заявке, счёте и карточке контрагента, потому что эти модели читают значение из единого источника.


Три типа наследования в Odoo

Odoo поддерживает три разных вида наследования, и каждый по‑своему определяет поведение полей и структуру таблиц в базе данных.

1. Классическое наследование

Это самый распространённый сценарий: вы указываете _inherit без нового _name. Так вы расширяете существующую модель — добавляете поля и методы — и ничего не создаётся в базе дополнительно. Новые поля просто становятся частью оригинальной таблицы модели.


Большинство модулей расширяют стандартные модели именно так. Например, модуль CRM добавляет специфичные поля к res.partner, и эти поля хранятся в той же таблице, что и базовые поля партнёра.


2. Прототипное (копирующее) наследование

Если вы используете одновременно _inherit и _name, создаётся новая модель, копия структуры родителя, но со своей таблицей. Поля родителя дублируются в модели-потомке, и изменения в потомке не затрагивают родителя.


Этот подход реже используется для простых доработок, но удобен, когда нужно получить самостоятельную модель с той же структурой, что и у существующей.


3. Делегирующее наследование

Особенность определяется через _inherits. В этом случае модель-потомок содержит Many2one‑ссылку на родителя и «прокси‑экспортирует» его поля как свои. Данные при этом остаются в таблице родителя, а потомок просто предоставляет к ним доступ через связь.

Именно этот тип обычно вкладывают в понятие «унаследованное поле» в строгом смысле: поле не копируется, оно читается и записывается через реляционную связь в родительской таблице.


Классический пример — связь между res.users и res.partner. Пользователь — это также контакт, и его имя, почта и телефон хранятся в записи партнёра, а пользователь получает к ним доступ через делегацию.

Как это поле работает


Как делегирование работает в глубине

Когда модель использует _inherits, ORM создаёт «прозрачный мост» между таблицами. При чтении унаследованного поля Odoo автоматически переходит по Many2one‑ссылке к родителю и возвращает значение, хранящееся там.


При записи значения через запись потомка система напрямую обновляет родительскую запись. Для разработчика поле выглядит «своим», но физически данные лежат в таблице родителя.


Из этого следует важный эффект: отсутствует дублирование данных. Обновили имя партнёра — изменение видно во всех местах, где на него ссылаются, включая записи пользователя, наследующего партнёра.


Классическое наследование и база данных

При классическом наследовании новые поля просто добавляются в таблицу исходной модели — дополнительной таблицы не создаётся. В базе расширенная модель и оригинал — одно и то же. Это самый простой и чистый путь добавления полей при кастомизации Odoo.


Related‑поля как лёгкая форма наследования

Поле с типом related — это вычисляемое поле, которое читает значение через цепочку реляций. По сути это не наследование моделей, но часто используется, чтобы «вывести» поле, хранимое в связанной записи, без изменения структуры текущей модели.


Например, на заказе продаж можно создать partner_country_id, которое читает partner_id.country_id. В интерфейсе оно выглядит как собственное поле заказа, но данные берутся из партнёра.

Related‑поля можно сохранять в БД через store=True. Это ускоряет поиск и фильтрацию, но увеличивает объём хранения и требует пересчёта при изменении источника.


Как поля резолвятся во время выполнения

При загрузке определения модели Odoo формирует полную карту полей, включая унаследованные. К моменту готовности модели каждая видимая колонка уже сопоставлена с её источником — будь то собственная таблица, таблица родителя через делегацию или цепочка related. Эта резолвка выполняется при старте сервера и кешируется для скорости.

Практические бизнес-сценарии


За техническими деталями стоит практическая польза: унаследованные поля помогают держать данные в одном месте и автоматически распространять изменения по системе без копирования.


1. CRM и продажи: контактные данные

Когда менеджер создаёт лид, имя клиента, телефон и почта подтягиваются из партнёра через Many2one. Обновили данные партнёра — все связанные лиды, предложения и заказы тут же видят новый адрес и телефон.


Здесь сочетаются классическое наследование и related‑поля: CRM расширяет res.partner своими метриками, а заказы выводят контактную информацию партнёра через related‑поля.


2. Товары и варианты

В механике товаров Odoo применяет делегирование для вариантов: product.product использует _inherits на product.template. Общие поля (название, категория, цена, описание) хранятся в шаблоне, а вариации содержат только отличающиеся атрибуты.


Это даёт возможность иметь десятки вариантов одной футболки, не дублируя название и описание по каждой записи в базе.


3. Пользователи и контакты

Каждый пользователь в Odoo — это контакт: res.users наследует поля res.partner через _inherits = {'res.partner': 'partner_id'}. Изменили e‑mail сотрудника — он поменяется и в настройках пользователя, и в адресной книге.


4. Склад: перемещения и информация о товарах

Линии перемещений в модуле Inventory получают описания товаров через цепочку related‑полей от шаблона товара. Менеджер склада всегда видит актуальное описание на путевом листе, без дублирования данных в модуле инвентаризации.


5. Бухгалтерия: строки проводок

Строки счета ссылаются на продукты и контрагентов. Название товара, счёт бухучёта и налоговые настройки отображаются через связи с моделями товара и партнёра. Бухгалтер видит данные, идентичные конфигурации товаров и продаж, потому что источники совпадают.

Создание и настройка унаследованных полей


Работа через Odoo Studio

Odoo Studio — это инструмент без кода для изменения моделей и представлений. Через Studio можно добавить поля в любую модель, не трогая Python. Под капотом Studio реализует классическое наследование, добавляя поле в определение модели.


В Studio также можно создать related‑поле. Выбирая тип «Related Field», вы указываете путь через связи от текущей модели к нужному полю — например, на заказе продаж указать страну или VAT клиента, взятую из партнёра.


Для большинства бизнес‑пользователей и консультантов Studio — оптимальный инструмент: оно автоматизирует нейминг, миграцию БД и размещение поля в представлениях.


Кастомизация через Python для разработчиков

Разработчики описывают унаследованные поля в Python через класс models.Model ORM Odoo.


Пример классического наследования для добавления поля в существующую модель:

class CrmLead(models.Model):
    _inherit = 'crm.lead'

    x_contract_value = fields.Float(
        string='Estimated Contract Value'
    )

Пример делегации для создания новой модели, которая разделяет поля существующей:

class EmployeeProfile(models.Model):
    _name = 'hr.employee.profile'
    _inherits = {'res.partner': 'partner_id'}

    partner_id = fields.Many2one(
        'res.partner',
        required=True,
        ondelete='cascade'
    )
    employee_id = fields.Many2one(
        'hr.employee',
        string='Employee'
    )

Пример related‑поля, которое подтягивает значение из связанной записи:

class SaleOrder(models.Model):
    _inherit = 'sale.order'

    partner_country_id = fields.Many2one(
        related='partner_id.country_id',
        string='Customer Country',
        store=True
    )

Через XML‑RPC API (удалённая конфигурация)

Поля также можно создавать программно через XML‑RPC и модель ir.model.fields. Это тот же эффект, что делает Studio, но доступный при удалённой настройке и при автоматическом деплое конфигураций.


Чтобы добавить related‑поле через API, создайте запись ir.model.fields с нужным типом (ttype='many2one' и т.д.) и укажите путь в параметре related. Такой подход удобен для автоматизированных установок и шаблонов конфигурации.

Рекомендуемые подходы


Выбирайте тип наследования, исходя из задачи

Если нужно просто добавить поле или метод в существующую модель — используйте классическое наследование: это проще и безопаснее. Делегирование применяйте только когда требуются два отдельных набора записей, связанные между собой, например когда бизнес‑сущность расширяет контакт, но не является им напрямую.


Предпочитайте related‑поля для доступа только на чтение

Если нужно лишь отображать значение из связанной записи в форме или списке, related‑поле предпочтительнее делегации: оно не создаёт дополнительной структурной зависимости и проще в поддержке.


Осторожно с store=True для related‑полей

Сохранение related‑поля в базе ускоряет фильтрацию, но превращает значение в копию. Odoo будет пересчитывать такие поля при изменении источника, и в редких случаях возможны рассинхроны. Храните related‑поля только если реально нужно фильтровать или группировать по ним в больших наборах данных.


Всегда префиксируйте кастомные поля x_

Любое поле, добавленное в стандартную модель, должно начинаться с x_ (или иметь неймспейс модуля). Это снижает риск конфликтов с будущими обновлениями Odoo.


Документируйте цепочку наследования

При сложных кастомизациях оставляйте комментарии или краткую схему, откуда берётся каждое поле. Поле с именем x_country_code на заказе может не явно ссылаться на partner_id.country_id.code, и документация спасёт следующего разработчика.


Правильно обрабатывайте каскадное удаление

В делегирующем наследовании родительская запись создаётся при создании дочерней. При удалении дочерней обычно нужно удалять и родителя — ставьте ondelete='cascade' на Many2one в _inherits, чтобы избежать «осиротевших» записей.


Типичные ошибки и подводные камни


Путаница между тремя типами наследования

Частая ошибка — использовать _inherit вместе с _name, когда на самом деле нужно простое расширение. Это создаёт новую модель вместо изменения существующей. Проверьте определение: если вы не хотите новой модели, уберите _name.


Забыть создать родителя при использовании _inherits

При делегировании родительская запись не всегда создаётся автоматически в кастомных сценариях. При создании через API или скрипт вы должны либо позволить ORM создать родителя, либо создать его заранее и передать ID. Иначе получите ошибку целостности данных.


Попытки изменить тип поля через наследование

Odoo не позволяет менять тип уже существующего поля через наследование. Можно изменить метаданные (label, domain, help), но не тип (например, Char → Integer). Попытка такого изменения приведёт к ошибке при установке модуля.


Чрезмерное использование store=True для related‑полей

Соблазн пометить все related‑поля как store=True ради производительности увеличит размер БД и усложнит поддержку. Если исходные поля часто меняются, пересчёты будут частыми. Используйте хранение выборочно.


Ожидание, что права доступа потомка применяются к полям родителя

Поля, полученные через делегацию, хранятся в модели родителя. Права доступа, заданные только для модели‑потомка, не защищают автоматически эти поля на уровне родителя. Если вы ограничиваете доступ к потомку, проверьте и правила безопасности для родителя, иначе пользователи могут получить доступ к данным напрямую через родительскую модель.

Выводы


Унаследованные поля — не частная, а фундаментальная часть архитектуры Odoo. Связь пользователей с контактami, вариантов с шаблонами, заказов с контактной информацией — всё это держится на механизмах наследования, которые поддерживают целостность данных и избегают дублирования.


Понимание того, какой тип наследования использовать, когда удобнее related‑поле, и как это всё отражается в базе, сделает вас более эффективным кастомизатором Odoo: меньше багов, чище модель данных и меньше времени на отладку.


Главная мысль проста: ORM Odoo устроен так, чтобы данные хранились в одном месте и использовались везде. Это принцип унаследованных полей, который сохраняет согласованность модели данных по мере роста системы.

Нужна помощь с внедрением Odoo?


В Dasolo мы помогаем компаниям внедрять, настраивать и оптимизировать Odoo. Если вы строите модуль с нуля, расширяете стандартные модели или пытаетесь понять загадочное поведение модели данных — у нас есть практический опыт, чтобы ускорить проект и избежать дорогостоящих ошибок.


Если у вас есть вопросы по модели данных Odoo, стратегии кастомных полей или технической реализации — мы готовы обсудить вашу задачу. Свяжитесь с нами и вместе найдём оптимальный путь для вашего проекта.

Наследуемые поля в Odoo: как ORM передаёт данные между моделями
Dasolo 6 марта 2026 г.
Поделиться этой записью
Войти оставить комментарий