You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo @api.onchange执行后自定义字段未在表单界面更新问题

问题根源

你遇到的UI不更新问题是Odoo onchange机制的固有特性导致的,核心原因有3个:

  • @api.onchange 触发时,你操作的是前端暂存在内存里的虚拟记录,不管是当前编辑的发票行,还是关联的父级发票单,此时都没有写入数据库。你代码里调用的rec.move_id.write()是直接修改数据库里的存量值,但当前打开的表单前端拿的是本地缓存的编辑态数据,不会主动重新读数据库,自然看不到变化。如果是还没点过保存的新建发票,move_id甚至是没有真实数据库ID的虚拟记录,这时候write调用根本不会生效。
  • 子表(One2many类型的发票行)触发的onchange,默认只会把当前行的字段变更返回给前端渲染,不会自动把父表(发票单)的字段变更通知给前端,哪怕你在内存里给父字段赋了值,前端收不到更新指令就不会刷新对应控件。
  • 你同时写了rec.move_id.global_discount=0(改内存缓存)和write(改数据库),两套操作数据源完全分离,很容易导致缓存和数据库值不一致,反而加重显示异常。
解决方法

修复onchange写法

注意:禁止在onchange方法中调用write、create这类直接操作数据库的方法,这类方法会绕过前端缓存直接改库,必然会导致界面显示和数据库数据不一致的问题。
onchange本身是保存前的预览交互逻辑,所有修改都应该在内存层面完成,等用户主动点保存时才会统一落库。修正后的代码如下:

from odoo import models, fields, api

class SoftOneInvoiceLine(models.Model):
    _inherit = "account.move.line"

    change_from_user = fields.Boolean('Change by user', default=True)

    @api.onchange('quantity', 'discount', 'price_unit', 'tax_ids')
    def _onchange_price_subtotal(self):
        super()._onchange_price_subtotal()
        for rec in self:
            if rec.change_from_user:
                # 仅修改内存中父记录的缓存值,不要写库
                rec.move_id.global_discount = 0
            rec.change_from_user = True

如果改完还是不刷新,说明你用的Odoo版本前端one2many渲染器没有自动追踪父级字段变更,可以在onchange返回值里手动加更新标记,强制前端刷新父表单。

更稳妥的长期方案

不要用onchange实现这个逻辑,直接在account.move模型上把global_discount设为计算字段,依赖发票行的对应字段,Odoo的ORM会自动处理所有更新、同步、UI刷新逻辑,完全不会出现缓存不一致的问题,示例代码:

from odoo import models, fields, api

class SoftOneInvoice(models.Model):
    _inherit = "account.move"

    global_discount = fields.Float(
        string='Global Discount',
        compute='_compute_global_discount',
        store=True,
        readonly=False  # 允许用户手动修改
    )

    @api.depends('invoice_line_ids.quantity', 'invoice_line_ids.discount', 
                 'invoice_line_ids.price_unit', 'invoice_line_ids.tax_ids')
    def _compute_global_discount(self):
        for move in self:
            # 这里可以加你需要的判断逻辑,配合change_from_user标记决定何时重置折扣
            move.global_discount = 0

如果需要保留用户手动修改global_discount的能力,保留readonly=False参数即可。


内容的提问来源于stack exchange,提问作者Panagiotis Anagnostakis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.08 16:15:17