Введение
Если вы работали с моделью данных в Odoo, наверняка сталкивались с ситуацией, когда нужно показать на форме значение, хранящееся в связанном документе, не перебирая записи вручную. Для таких задач в Odoo существует Related-поле — декларативный способ «подтянуть» значение из другой модели прямо на текущую форму.
Вместо того чтобы писать вычисляемое поле с Python-методом, Related-поле просто проходит по цепочке связей и показывает итоговое значение. Это очень удобный инструмент как для разработчиков, так и для консультантов, которые используют Odoo Studio и хотят добавить контекстную информацию без программирования.
В этом материале мы разберём, что именно хранит Related-поле, как оно работает внутри ORM Odoo, как его создать через Studio и в коде, и в каких рабочих сценариях оно окажется полезным.
Что такое Related-поле в Odoo
В ORM Odoo Related — это не отдельный тип данных наподобие Float или Char, а скорее «ярлык», который ссылается на поле другой модели. Фактически поле наследует тип конечного поля в цепочке связей и отображает его значение на текущей модели.
Простой пример: в заказе на продажу есть поле partner_id (Many2one на res.partner). Related-поле с связью partner_id.country_id выведет страну клиента прямо в форме заказа — без дублирования данных в новой колонке.
С точки зрения интерфейса Related-поле выглядит как обычное поле формы: если на конце цепочки Char — вы получите текстовое поле, Many2one — выпадающий список, Boolean — флажок. Визуально оно повторяет поведение того поля, на которое ссылается.
По умолчанию Related-поля являются только для чтения и не сохраняются в БД. Это значит, что они всегда показывают актуальное значение из источника, но не подходят для прямой фильтрации или группировки, если не включить store=True.
В Odoo Studio создание Related-поля максимально простое: при добавлении поля выбираете путь связей, и Studio автоматически создаёт поле с нужной конфигурацией — удобный вариант для консультантов, которые хотят быстро дополнить форму без кода.
Принцип работы поля Related
Когда Odoo читает Related-поле, оно проходит по именам полей, разделённым точками. Все звенья, кроме последнего, должны быть реляционными (Many2one, One2many, Many2many), а заключительное звено может быть любого типа.
Ниже приведён типовой пример определения Related-поля в модуле на Python.
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
partner_country_id = fields.Many2one(
related='partner_id.country_id',
string='Customer Country',
store=True,
)
В этом фрагменте Odoo сперва переходит по partner_id к записи res.partner, затем читает country_id и в итоге отображает Many2one-поле с информацией о стране на уровне заказа.
Сохранённые и несохранённые Related-поля
Главное различие — по умолчанию store=False: значение вычисляется «на лету» при чтении записи и не хранится в таблице модели.
Если указать store=True, значение будет записываться в колонку БД при изменении источника. Это даёт возможность фильтровать, группировать и искать по полю — важно для отчётов и списков.
Минус в том, что хранимые Related-поля занимают место в БД и требуют триггера обновления при изменениях источника. Odoo автоматически отслеживает зависимости, но при больших объёмах данных стоит учитывать нагрузку.
Только для чтения и записываемые Related-поля
По умолчанию Related-поля только для чтения. Если задать readonly=False, поле становится редактируемым: при изменении Odoo запишет новое значение обратно по цепочке в исходную запись. Это удобно, но может удивить пользователя, потому что изменение на форме заказов фактически меняет связанную запись партнёра.
Используйте writable Related-поля только когда намерение — запись в исходный объект. Для быстрых правок в списке это удобно, но при нечётком понимании бизнес-пользователями приведёт к непредвиденным изменениям общих данных.
Ключевые атрибуты поля
Ниже перечислены основные параметры, которыми управляют Related-полем:
- related: цепочка имен полей через точки (например, 'partner_id.country_id'). Это обязательный параметр.
- store: True — сохранять значение в БД для возможности фильтрации и группировки.
- readonly: False — позволить редактировать поле, что приведёт к записи в исходную модель.
- string: подпись поля, видимая пользователю; по умолчанию берётся от конечного поля.
- depends: обычно не нужен, так как Odoo сам выводит зависимости из related-цепочки; пригоден в редких, специфичных случаях.
Взаимодействие с ORM Odoo
Чтение Related-поля возвращает значение конечного поля в связанной записи. Если какой-то звено цепочки пустое (например, partner_id не задан), результатом будет False — стандартная логика ORM для реляционных полей.
Если поле сохранено (store=True), его можно использовать в доменах, представлениях и отчётах. Несохранённые поля отображаются в форме и списке, но не служат критерием поиска, пока сервер не оценит их на стороне Python вместо SQL.
Бизнес-кейсы применения
Related-поля встречаются почти во всех частях Odoo. Ниже — пять практических сценариев из реальных бизнес-процессов.
CRM и продажи: телефон клиента в заказе
Отдел продаж часто просит видеть телефон покупателя прямо на форме заказа. Related-поле с partner_id.phone решает это за пару кликов: телефоны отображаются в контексте заказа, ускоряя прозвон и убирая необходимость открывать карточку партнёра. В Studio такую настройку можно сделать за минуту.
Бухгалтерия: валюта компании в строках счёта
В мультикомпанейных конфигурациях бухгалтерам удобно видеть валюту компании на строках счёта. Related-поле, например move_id.company_id.currency_id, проходит по двум связям и показывает валюту. Хотя цепочки на два шага работают нормально, длинные цепочки лучше держать в рамках ради производительности. Сохранённое поле позволяет фильтровать и группировать проводки по валюте в аналитических отчётах.
Склад: категория товара в записях перемещения
Складские операторы порой нуждаются в категории товара прямо в строке stock.move.line, чтобы не заходить в карточку продукта. Related-поле product_id.categ_id предоставляет эту информацию. При store=True вы сможете группировать перемещения по категориям в отчётах Инвентаря — это полезно при большом ассортименте.
Производство: внутренний код на компонентах рабочего задания
В производстве оператору на участке важно видеть внутренний артикул компонента прямо в списке операций. Related-поле product_id.default_code на строке mrp.workorder даёт этот артикул в нужном месте, сокращая ошибки при подборе похожих деталей и повышая точность сборки.
Таймшиты и проекты: подразделение сотрудника
Руководитель проекта при анализе учёта рабочего времени часто хочет видеть, к какому отделу принадлежит сотрудник. Related-поле employee_id.department_id на account.analytic.line показывает отдел в строке таймшита. При store=True такие строки можно фильтровать по отделам в отчётах по проектам, что важно для распределения затрат и ресурсов.
Как создать или настроить Related-поле
Три способа добавить Related-поле в модель Odoo
Способ 1 — Odoo Studio (без кода)
Studio позволяет создать Related-поле без программирования. Алгоритм действий простой:
- Откройте Odoo Studio из главного меню.
- Перейдите на форму, куда хотите добавить поле.
- Нажмите «Добавить поле» и выберите «Related Field».
- Пошагово укажите путь связей, кликая по доступным полям.
- Задайте подпись и опции: хранить или только для чтения.
- Сохраните изменения и выйдите из Studio.
Studio создаст поле с префиксом x_studio_ и поместит его в представление. Это быстрый и гибкий способ добавить контекстные данные без вмешательства в базу или код.
Способ 2 — Python в кастомном модуле
Для разработчиков, которые работают через код и нуждаются в управляемой, версионируемой настройке, Related-поля объявляют в классе модели — это рекомендуемый подход для стабильных кастомизаций и деплоя в несколько окружений:
from odoo import fields, models
class StockMoveLine(models.Model):
_inherit = 'stock.move.line'
product_category_id = fields.Many2one(
related='product_id.categ_id',
string='Product Category',
store=True,
)
После объявления добавьте поле в XML представление, чтобы оно стало видимым в интерфейсе. При установке или обновлении модуля Odoo сам создаст колонку в базе — стандартный путь для поддерживаемых кастомизаций.
Способ 3 — через XML-RPC API
Если конфигурация управляется программно (например, автоматизированные скрипты развёртки), Related-поля можно создать через XML-RPC, задав атрибут related в определении поля.
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_partner_country_id',
'field_description': 'Customer Country',
'model_id': sale_order_model_id,
'ttype': 'many2one',
'relation': 'res.country',
'related': 'partner_id.country_id',
'store': True,
'readonly': True,
'state': 'manual',
}]
)
При создании через API нужно вручную указать ttype и relation, потому что API не выводит тип из цепочки так, как это делает Python ORM. Такой подход удобен для автоматизированного развёртывания полей в нескольких базах.
Рекомендации по использованию
Практические правила
1) Ставьте store=True, если поле будет использоваться в фильтрах или группировках. Без этого Odoo не сможет применить такой фильтр на уровне БД, и попытки поиска будут либо неэффективны, либо неверны. Для информационных полей в форме хранение необязательно.
2) Держите цепочку короткой. Двухуровневая цепочка (partner_id.country_id) — оптимальна. Глубокие цепочки сложнее отлаживать и более подвержены ошибкам; если требуется сложная логика, рассмотрите вычисляемое поле на Python.
3) Чётко понимайте значение readonly=False. Редактируемое Related-поле не копирует данные локально — оно правит исходную запись. Убедитесь, что пользователи осознают, что правки затронут общий объект.
4) Используйте Related-поля для отображения данных, а не для их дублирования. Если нужен независимый от источника столбец — лучше обычное поле с заполнением через onchange или автоматизацию, а не Related с store=True и readonly=False.
5) Проверьте права доступа. Если у пользователя нет прав чтения на промежуточную модель, Related-поле будет пустым. Это корректное поведение безопасности, но может запутать пользователей; предусмотрите соответствующие роли и тесты.
Распространённые ошибки
Фильтрация по несохранённому Related-полю
Одна из самых частых проблем — добавление Related-поля в список и попытка сразу же использовать его в поиске. Если store=False, фильтр не сработает на уровне SQL: домен вернёт ошибку либо пустой результат. Всегда ставьте store=True для полей, по которым будете фильтровать или группировать.
Неожиданная запись в исходную модель
Типичные ошибки и ловушки
Ещё частая ловушка — сделать Related-поле редактируемым и удивиться, что изменение затронуло исходный объект (например, партнёра). Это особенно характерно для полей, созданных через Studio пользователями без технического опыта. Перед включением возможности редактирования согласуйте поведение с бизнесом.
Пустые промежуточные звенья в цепочке
Если любое звено цепочки пустое, Related-поле вернёт False и на форме отобразится пустая ячейка. В коде, который читает это поле, нужно обрабатывать такой случай, иначе можно получить TypeError. Эту ситуацию легко пропустить в тестах, когда у тестовых записей все поля заполнены, но она проявится в продакшене.
Использование Related там, где нужен computed-подход
Related-поля хороши для простого «подтягивания» значения. Если требуется трансформация, условная логика или несколько источников — лучше писать computed-поле на Python. Попытки обойти ограничения Related-цепочки ведут к хрупким решениям, которые ломаются при обновлениях Odoo.
Проблемы с производительностью при большом количестве сохранённых Related-полей
Каждое store=True Related-поле требует обновления при изменении источника. Если на модели повешено много таких полей и объём записей большой, это создаёт значительную нагрузку на запись в БД. Для масштабных решений профилируйте влияние и отдавайте предпочтение несохранённым полям, если не нужна моментальная точность данных.
Итог — когда стоит использовать Related-поле
Related-поле — эффективный инструмент для вывода контекстной информации без дублирования. Оно позволяет пройти по цепочке связей, показать связанные значения в любом представлении и при необходимости сохранить их для отчётности и поиска.
Понимание момента, когда включать store=True, когда разрешать запись через readonly=False и как обрабатывать пустые промежуточные звенья, поможет избежать распространённых проблем при внедрении Odoo. Независимо от того, пишете ли вы модули на Python, делаете кастомизацию через Studio или управляете конфигурациями удалённо, Related-поле стоит держать в арсенале.
Заключение
Если вы проектируете или расширяете модель данных в Odoo, Related-поля должны соседствовать в вашем наборе инструментов с computed-полями, Many2one и другими типами полей, о которых идёт речь в этой серии.
В компании Dasolo мы помогаем внедрять, настраивать и оптимизировать Odoo для отделов продаж, операций, бухгалтерии и других подразделений. Если нужна помощь с проектированием модели данных, добавлением кастомных полей или расширением Odoo надёжным кодом — можем взять это на себя.
Свяжитесь с нами
и обсудим, как поддержать ваш Odoo-проект. Свяжитесь с нами и обсудим, чем можем помочь в реализации вашего проекта на Odoo.