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

Odoo中如何保存new()方法创建的对象以获取真实记录ID

问题根源

对Odoo ORM的new()方法定位存在理解偏差:

  • new()生成的是仅存在于当前内存上下文的虚拟临时记录,全程不会触发任何数据库写入,返回的id是系统自动生成的临时占位值(通常为负数格式的NEWID),不存在对应的真实数据库行。
  • 之前尝试使用的save()方法仅存在于ORM测试场景的模拟游标环境中,常规业务运行环境的模型对象没有这个方法,无法直接用来持久化临时记录。
持久化实现思路

你现在用new()的核心目的,是在不提前写库的前提下,复用现有模型的onchange、计算字段逻辑把发票头字段、行项目的计算结果算对,最终目标是把这些内存中算好的有效字段值,通过Odoo标准的ORM创建流程写入数据库,拿到真实的记录ID。
具体流程按以下步骤调整原有代码即可:

  • 完整保留原有逻辑:跑完所有临时对象的字段赋值、onchange计算触发(包括给new_line设account_id、触发价格小计计算、触发税费重算等流程)
  • 将临时vendor_bill上经过onchange计算得到的有效业务字段,转换成可用于创建真实记录的字段字典
  • 将所有临时生成的new_line的字段值,按照Odoo o2m字段的创建命令格式整理成行数据列表
  • 调用标准create方法生成真实的account.move记录,该记录会自动分配真实的数据库ID,完全匹配后续业务流程的调用要求。
调整后的参考代码
# Create vendor bill
# 原有临时对象生成逻辑完全保留,用于触发onchange计算
vendor_bill = self.env['account.move'].with_context({'check_move_validity': False}).new(values)
po_lines = purchase_orders.mapped('order_line')
new_lines = self.env['account.move.line']
for line in po_lines.filtered(lambda l: not l.display_type):
    new_line = new_lines.new(line._prepare_account_move_line(vendor_bill))
    new_line.account_id = new_line._get_computed_account()
    new_line._onchange_price_subtotal()
    new_lines += new_line
new_lines._onchange_mark_recompute_taxes()

# 新增:将临时对象的计算结果导出,生成真实可持久化的字段值
# 1. 提取临时发票头的有效字段,自动适配数据库写入格式
bill_header_vals = vendor_bill._convert_to_write(vendor_bill._cache)
# 2. 提取临时发票行的字段值,转换成create要求的o2m命令格式
bill_line_vals = [
    (0, 0, line._convert_to_write(line._cache))
    for line in new_lines
]
bill_header_vals['invoice_line_ids'] = bill_line_vals

# 新增:创建真实的发票记录,直接获取真实数据库ID
real_vendor_bill = self.env['account.move'].with_context({'check_move_validity': False}).create(bill_header_vals)
关键注意事项
  • 上述代码中使用的_convert_to_write(cache)方法是Odoo ORM内置的字段格式转换方法,可以把临时记录缓存中存储的字段值自动转换成符合数据库写入要求的格式,不需要手动逐个字段适配类型(比如关联字段的ID、金额类型的精度处理等)。
  • 原有代码中添加的check_move_validity: False上下文可以在create环节继续保留,避免创建阶段触发的合规校验阻断流程。
  • 你所有在临时对象上触发的onchange、计算字段逻辑的运行结果,都会通过字段缓存完整保留在导出的字典中,不会破坏原本参照_onchange_purchase_auto_complete实现的自动计算逻辑。
  • 不要直接对临时对象调用flush()或者save()方法,这类操作在常规生产运行环境下没有合法的执行路径,只会抛出ORM方法不存在的报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 19:27:04