2025, Dec 28 21:02

Мгновенное обновление вычисляемых полей в Odoo: onchange + depends

Почему compute-поле в Odoo пусто на новой форме и как обновлять его мгновенно через onchange, сохраняя depends. В статье есть пример с related-полем. Гайд.

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

Постановка задачи

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

from odoo import api, fields, models

class AssetLine(models.Model):
    _name = 'asset.line'

    parent_ref = fields.Many2one('job.request', string='Request', required=True)
    asset_label = fields.Char('Nama Asset', store=False, compute='_calc_label')

    @api.depends('parent_ref')
    def _calc_label(self):
        for rec in self:
            req = rec.parent_ref
            rec.asset_label = req.equipment_id.name

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

Что происходит

Метод вычисления, связанный с depends, выполняется при записи значений в базу данных. В совершенно новой форме, которую ещё не сохраняли, одного взаимодействия в интерфейсе недостаточно, чтобы запустить вычисление. Поэтому поле выглядит пустым, пока пользователь заполняет форму. В этот момент родитель может быть не установлен, из‑за чего выражение фактически даёт False, и метка остаётся пустой. После сохранения вычисление срабатывает — поэтому на существующих данных всё работает.

Для новых записей (и динамики в веб-интерфейсе!) используйте onchange; всегда предполагайте, что кто‑то создаст запись из кода, поэтому сохраняйте и depends.

Решение

Запускайте вычисление в браузере при изменении родительского поля и сохраняйте зависимость для корректности при работе из кода или при сохранении. Связка onchange для интерактивности и depends для согласованности покрывает оба сценария.

from odoo import api, fields, models

class AssetLine(models.Model):
    _name = 'asset.line'

    parent_ref = fields.Many2one('job.request', string='Request', required=True)
    asset_label = fields.Char('Nama Asset', store=False, compute='_calc_label')

    @api.onchange('parent_ref')
    @api.depends('parent_ref')
    def _calc_label(self):
        for rec in self:
            req = rec.parent_ref
            rec.asset_label = req.equipment_id.name

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

from odoo import fields, models

class AssetLine(models.Model):
    _name = 'asset.line'

    parent_ref = fields.Many2one('job.request', string='Request', required=True)
    asset_label = fields.Char(related='parent_ref.equipment_id.name')

Почему это важно

Одна лишь depends ведёт к пустым полям на новых формах, заставляя пользователей гадать и перепроверять данные после сохранения. Добавление onchange даёт мгновенную обратную связь при вводе, а сохранение depends гарантирует корректность, когда записи создаются или меняются из кода. Да, при сохранении вычисление всё равно выполнится, но пользователям не должно приходиться ждать, чтобы увидеть, что они выбрали.

Выводы

Для полей, которые на новой записи должны сразу отражать выбор родителя, используйте onchange вместе с depends. Если поле — просто «пропуск» атрибута родителя, отдайте предпочтение related‑полю: модель получится короче и проще в сопровождении. Эта небольшая доработка убирает путаницу, исключает догадки до отправки формы и обеспечивает единообразие данных вне зависимости от способа создания записей.