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

One2many в Odoo: Полное руководство по полю One2many

Поясняю, как работает поле One2many в Odoo, в каких ситуациях оно пригодится и как правильно встроить его в модель данных. Это не просто связь «один ко многим» в чистом виде — это удобный инструмент для организации списков связанных записей, например строк заказов у одного счета или заметок у клиента. Разберёмся, когда стоит выбрать One2many вместо других типов связей, какие есть подводные камни (производительность, каскадные удаления, валидация) и какие поля и констрейнты нужно добавить в модели. Также покажу типичную реализацию: определение поля в родительской модели, соответствующее поле Many2one в дочерней модели, пример XML/ORM-кода для создания и отображения списка в форме, а также советы по записи и обновлению связанных записей через create/write и odoo API. В результате вы получите понятную инструкцию, когда и как применять One2many для упорядочивания связанных данных в Odoo без утечки производительности и логических ошибок.
6 марта 2026 г. от
One2many в Odoo: Полное руководство по полю One2many
Dasolo
| Комментариев пока нет

Введение


Если вы когда-нибудь открывали заказ продаж в Odoo и видели список строк заказа под данными клиента — вы на практике сталкивались с полем One2many. Это одна из ключевых конструкций в модели данных Odoo: она отвечает за отображение и управление связями «родитель — множество дочерних записей», с которыми ежедневно работают пользователи и разработчики.


В этой статье мы разберём, что такое One2many, как он реализован в ORM Odoo, в каких случаях стоит использовать это поле и как его правильно создать — через Odoo Studio или напрямую в Python-коде в модуле.

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

Что такое поле One2many в Odoo


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


Проще говоря: одна компания может иметь множество счетов, один заказ — множество строк заказа, один проект — множество задач. One2many служит для представления таких «списков» дочерних элементов внутри родительского объекта.


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


Чем он отличается от других реляционных полей

В ORM Odoo есть три основных типа реляционных полей:


  • Many2one: одиночная ссылка на одну запись в другой модели (например, заказ указывает на одного клиента).
  • One2many: ссылка одного родителя на много дочерних записей (например, заказ связан со множеством строк заказа).
  • Many2many: взаимные связи «многие ко многим» (например, товар может иметь несколько тегов, и тег может быть у многих товаров).

One2many применяют, когда каждая дочерняя запись принадлежит ровно одному родителю. Если запись должна одновременно относиться к нескольким родителям, нужно использовать Many2many, иначе придётся дублировать данные.


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

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


На уровне базы данных колонок для One2many в таблице родителя не создаётся: связь реализована через внешний ключ в таблице дочерних записей, указывающий на ID родителя.


Это базовый принцип ORM Odoo: каждая One2many имеет обратное поле Many2one в связанной модели. Фактически One2many — это обратный поиск: Odoo находит все дочерние строки, у которых поле Many2one совпадает с ID текущего родителя.


Взаимосвязь One2many и Many2one

При определении One2many в Python задают два основных параметра:


  • comodel_name: модель, где находятся дочерние записи.
  • inverse_name: имя поля Many2one на дочерней модели, указывающего на родителя.

Ниже — типичный пример из кастомного модуля, где договор сервиса связан со списком артефактов (deliverables):


deliverable_ids = fields.One2many(
    comodel_name='service.deliverable',
    inverse_name='contract_id',
    string='Deliverables'
)

В этом примере contract_id — это поле Many2one на модели service.deliverable, которое указывает на контракт. Без такого обратного поля One2many просто не сможет работать.


Что реально происходит в базе данных

В базе данных Odoo информация по One2many хранится не в таблице родителя, а в таблице дочерних объектов: каждая дочерняя строка содержит столбец-внешний ключ, указывающий на ID родителя.

Когда Odoo загружает родительскую запись и нужно показать её One2many, ORM выполняет SQL-запрос: найти все строки в таблице child, где внешний ключ равен ID текущего родителя. Это стандартное поведение реляционных СУБД, которое Odoo скрывает за удобным API.


Именно поэтому One2many считается полем, которое не добавляет колонок в таблицу — это вычисляемое представление связанных записей.

Бизнес-сценарии применения


One2many встречается повсеместно в Odoo, поскольку естественно моделирует отношения «родитель — дети» в бизнес-процессах. Ниже — пять типичных примеров из реальной практики.


1. Заказы продаж и строки заказа

В модуле продаж модель sale.order использует One2many order_line_ids, ссылающийся на sale.order.line. Каждая строка хранит сведения о товаре, количестве, цене и скидках. Пользователь может прямо в форме заказа добавлять или удалять строки без лишних переходов.


2. Счета и строки счёта

В бухгалтерии модель account.move содержит One2many на строки счёта (account.move.line). Каждая строка — это начисление по продукту или услуге; родительский счёт аккумулирует суммы из всех своих строк.


3. Проекты и задачи

В проектном модуле у project.project есть One2many для задач; в форме проект может показывать задачи списком, канбаном или диаграммой Ганта — всё это разные представления одной и той же One2many-связи.


4. Контрагенты и контактные лица

Модель res.partner содержит поле child_ids, которое перечисляет контактных лиц компании. В карточке компании вкладка "Контакты" показывает всех сотрудников и контактных ответственных; у каждого из них есть Many2one parent_id, указывающий на компанию.


5. Пользовательские модели в сервисе или производстве

При создании своего модуля One2many — естественный выбор, когда одна запись владеет списком подзаписей: заявка на обслуживание с перечнем запасных частей, курс со списком дат сессий, договор с перечнем результатов работ и т.п.


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

Создание и настройка поля


Добавить One2many можно двумя способами: через Odoo Studio без кода или написав поле в Python в кастомном модуле.


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

В Studio нельзя сразу создать One2many на родительской модели из палитры полей, потому что One2many всегда опирается на уже существующий Many2one на дочерней модели.

Рекомендуемый порядок действий в Studio:

  1. Сначала откройте дочернюю модель и добавьте в ней поле Many2one, указывающее на родителя.
  2. После сохранения вернитесь к родительской модели в Studio.
  3. Добавьте новое поле типа "One2many"; Studio попросит указать связанную модель и имя inverse (Many2one).
  4. После этого One2many появится во встроенном списке на форме родителя.

Для пользователей, не пишущих код, этот путь — самый простой: Studio создаёт поля, которые по поведению полностью эквивалентны полям, описанным в Python.


Определение в Python в кастомном модуле

Разработчикам удобнее и правильнее задавать One2many в коде, поскольку так доступен полный контроль над поведением, именованием и доп. ограничениями. Пример полного определения выглядит так:


from odoo import fields, models

class ServiceContract(models.Model):
    _name = 'service.contract'
    _description = 'Service Contract'

    name = fields.Char(string='Contract Name', required=True)
    deliverable_ids = fields.One2many(
        comodel_name='service.deliverable',
        inverse_name='contract_id',
        string='Deliverables'
    )


class ServiceDeliverable(models.Model):
    _name = 'service.deliverable'
    _description = 'Service Deliverable'

    contract_id = fields.Many2one(
        comodel_name='service.contract',
        string='Contract',
        ondelete='cascade'
    )
    name = fields.Char(string='Description', required=True)

Обратите внимание: поле Many2one (contract_id) должно быть определено в дочерней модели. Имя, указанное в inverse_name, должно точно совпадать с именем Many2one, иначе связь не заработает.


Создание поля через XML-RPC API

Если вы управляете полями Odoo программно, можно создавать One2many через XML-RPC, создавая записи в ir.model.fields. Принцип тот же: сначала создаёте Many2one, затем — One2many, указывая relation_field с именем обратного поля.


Такой подход полезен при автоматизации изменений структуры базы в разных окружениях или при массовом создании полей в нескольких БД.

Рекомендации по использованию


Из практики внедрений — набор правил, которые реально экономят время и сокращают ошибки при работе с One2many.


  • Всегда создавайте Many2one в первую очередь. One2many не может существовать без обратного поля. Это относится ко всем сценариям — Studio, Python или API.
  • Используйте суффикс _ids для имён One2many. Принято называть такие поля с суффиксом _ids (например, line_ids, task_ids), чтобы сразу было понятно, что поле возвращает набор записей.
  • Применяйте ondelete='cascade', когда нужно. Если дочерние записи должны удаляться вместе с родителем, укажите это в Many2one — так вы избежите «осиротевших» строк в БД.
  • Фокусируйте список One2many на главном. Показывайте только ключевые колонки в встроенном списке: слишком много полей в One2many замедляет форму и снижает юзабилити. Для второстепенных колонок используйте опцию optional, чтобы пользователь мог включать их по необходимости.
  • Ограничивайте видимые дочерние записи через domain. Добавление domain к One2many помогает фильтровать дочерние записи по условию, что особенно важно, если та же модель используется несколькими родителями.
  • Аккуратно работайте с большими объёмами данных. Если у родителя потенциально тысячи дочерних записей, не загружайте их все в форме. Рассмотрите отдельный список или постраничность для вложенной таблицы.

Распространённые ошибки


Типичные ошибки при работе с One2many — они повторяются у многих команд и проектов.


Забывают создать обратный Many2one

Самая частая ошибка — попытка добавить One2many без существующего Many2one на дочерней модели. Odoo вернёт ошибку. Всегда проверяйте, что inverse_name действительно существует на дочерней модели.


Неверный синтаксис при записи данных

При обновлении One2many через код или API нужно использовать специальные команды (command tuples). Нельзя просто присвоить обычный Python-список. Правильные операции выглядят так:


  • (0, 0, values_dict) — создать новую дочернюю запись.
  • (1, child_id, values_dict) — обновить существующую дочернюю запись.
  • (2, child_id, 0) — удалить существующую дочернюю запись (и саму запись).
  • (4, child_id, 0) — добавить существующую запись в отношение без создания копии.
  • (5, 0, 0) — разорвать все связи (unlink связей) между родителем и дочерними записями, но не удалять сами дочерние записи.

Попытка писать простой список вроде record.line_ids = [1, 2, 3] не сработает как ожидается в ORM Odoo.


Путаница между One2many и Many2many

Если дочерняя запись должна принадлежать нескольким родителям одновременно, One2many не подойдёт — используйте Many2many. Попытки моделировать множественные связи через One2many ведут к дублированию данных и проблемам целостности.


Проблемы с производительностью при больших вложенных списках

Если в One2many показываются сотни или тысячи строк, загрузка формы существенно замедляется — это часто встречается в учёте и инвентаризации. Применяйте ограничение (limit) в представлении или направляйте пользователя на отдельный список для обработки больших наборов данных.


«Осиротевшие» записи после удаления родителя

Если удалить родителя, не настроив ondelete='cascade' в Many2one, дочерние записи останутся с пустым или некорректным ссылочным полем. Со временем это засоряет базу и может приводить к ошибкам в отчётах и видах. Планируйте политику удаления заранее.

Заключение


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


Независимо от того, настраиваете ли вы систему через Studio, пишете модуль с нуля или администрируете существующую базу, One2many будет инструментом, к которому вы будете возвращаться постоянно. Знание, когда и как его правильно применять, а также умение избегать типичных ошибок сэкономит время и уберегёт данные.

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

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


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

Если у вас есть вопросы по проекту Odoo или вы хотите обсудить структуру данных, свяжитесь с нами— мы будем рады помочь.

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