导言
每张 Odoo 表单都由若干字段构成。有些字段每次都得手动输入,但很多字段可以提前填上合理的初始值,让用户打开表单时就看到有用的预设内容。Odoo 的默认值机制看起来很简单,但在配置或定制表单时,有几层行为逻辑值得理解,否则容易在实际使用中遇到难查的配置问题。
无论你是通过 Odoo Studio 为团队做无代码调整的业务人员,还是编写模块的开发者,掌握默认值如何生效能节省大量时间,并避免运行中出现的“看不见”的配置冲突。
本文将介绍 Odoo 中默认值的概念、ORM 层如何应用默认值、静态与动态默认值的使用时机,以及如何通过 Odoo Studio 或 Python 在项目中配置默认值。
什么是 Odoo 中的默认值
在 Odoo 的 ORM 里,默认值是新建记录时系统预先赋给字段的初始数据——用户还未输入任何内容。它不是约束,用户可以随意修改;它的作用只是让表单初始状态更贴合常用场景,从而提升效率与一致性。
在 Odoo 框架中,几乎所有字段类型都支持 default 参数:字符、整数、浮点、布尔、日期、Many2one、Selection 等。默认值既可以是固定常量,也可以是 Python lambda 或方法引用。根据实际需求可以选择不同的默认实现方式。
对于不擅长写代码的业务用户,Odoo Studio 提供了可视化的默认值设置面板,可以直接为字段指定静态默认。通过 Studio 设置默认值是改善数据一致性的低门槛手段,无需开发参与。
默认值并不会直接存储在数据库表的字段列上。它们要么来自于 Python 模型定义,要么以 ir.default 记录保存在数据库中,具体取决于你如何配置。新建记录时,Odoo 会读取这些来源并在表单展示前进行预填充。
默认值的工作原理
当用户打开新建表单时,框架会调用模型的 default_get() 方法来收集默认值。该方法返回一个以字段名为键、默认值为值的字典,前端据此对表单字段进行预填。
Odoo 中主要存在四类默认值来源,各自适用于不同场景。
静态默认
静态默认指在字段定义或 Studio 中写死的固定值,例如把某布尔字段默认设为 True,或把状态型 Selection 字段默认设为 'draft'。这是最简单也最常见的用法,适用于多数日常需求。
通过 lambda 或方法的动态默认
动态默认通过运行 Python 函数或 lambda 在记录创建时计算值,常见用于依赖当前日期、当前用户或上下文信息的场景。比如把当前登录用户设为默认负责人,或把当天日期设为单据默认日期。
在 Python 模型中,静态和动态默认通常以字段定义里的 default 参数表达,遵循 Odoo 开发常规。
示例(仅示意说明思路):
from odoo import fields, models
class CrmLead(models.Model):
_inherit = 'crm.lead'
# 静态默认
x_priority_level = fields.Selection(
[('low', '低'), ('medium', '中'), ('high', '高')],
string='优先级',
default='medium',
)
# 动态默认:当前用户
x_assigned_by = fields.Many2one(
'res.users',
string='分配人',
default=lambda self: self.env.user,
)
# 动态默认:今天日期
x_expected_date = fields.Date(
string='预计完成日期',
default=lambda self: fields.Date.today(),
)
基于上下文的默认值
通过 action context 传入的 default_field_name 约定可以在打开新表单时传递预设值。例如从某个项目记录内点“新建任务”时,项目字段会通过上下文自动填好。这种方式常用于导航或按钮触发的创建流程,任何开发者或高级用户都可以配置这些 context 键。
基于用户/公司级别的 ir.default
Odoo 允许通过 ir.default 为特定用户或公司设置个人化的默认值。管理员可以为某个字段在某个用户下配置默认值,该用户新建记录时优先使用该配置。这在多人协作或不同岗位偏好不同的场景里非常实用,也是 Odoo ORM 较少被注意到但很有价值的功能。
默认值优先级
当同一字段存在多个默认来源时,Odoo 会按一定优先级来选取:先应用用户级的 ir.default,再公司级 ir.default,最后才是模型中定义的 Python 默认;由运行时 context 传入的默认通常也会覆盖模型级默认。了解这个顺序有助于排查为什么新建表单没有显示你期望的值。
业务场景示例
默认值在 Odoo 的各个模块中随处可见,下面列举五个常见的实际业务示例。
CRM:新线索的默认销售负责人
当销售人员新建线索或机会时,通常希望负责人默认就是当前登录用户;这样不会出现大量未分配的线索需要额外分配。模型中用 lambda self: self.env.user 设置默认即可,实践中这能显著提升 CRM 的使用率。
销售:订单上的默认付款条件
为客户创建销售订单时,价目表和付款条件通常从客户档案继承过来。比如某客户设定为账期 30 天,系统在新订单中会自动填好该付款条件,避免不同销售人员手动选择出错,保证成交条款一致性。
库存:调拨的默认库位
生成内部调拨或库存调整单时,来源和目标库位可以默认到仓库设置里的常用区域。固定在同一作业区的仓库人员打开新调拨单时会发现库位已被正确预选,节省操作并降低填错库位的风险。
会计:凭证使用的默认日记账
新建客户发票或供应商账单时,系统会根据凭证类型与公司设置选择合适的日记账。会计人员无需每次手动挑选,从公司配置动态解析出的默认能在账簿重配置后仍然保持正确。
项目管理:新任务的默认阶段
在项目中创建任务时,任务默认进入该项目看板的第一个阶段;如果是从某个项目记录内点“新建任务”,上下文还会把项目、甚至指派人预填上。这样的默认设置能确保新任务一开始就处于合适的阶段,减少后续整理工作。
如何创建或自定义默认值
在 Odoo 中设置默认值有三种常见方式,从无代码的 Studio 设置到在 Python 模块里完全掌控。
使用 Odoo Studio(无代码)
Odoo Studio 提供可视化界面,让你在表单上直接为字段设定默认值。设置步骤很直观:
- 打开想修改的表单并进入 Studio 模式
- 点击要配置的字段
- 在右侧字段属性面板里找到“默认值”输入项
- 填写或选择你想要的初始值
- 保存并退出 Studio
Studio 实际上将该配置以 ir.default 的形式写入数据库,默认在公司范围内生效(可由管理员限定到用户)。这对 Selection、Boolean、Char、Integer 等静态默认非常适合,Many2one 字段可以从下拉中选定现有记录,是无需写代码即可改进数据一致性的常用做法。
需要注意的是:在已有记录大量存在的情况下,通过 Studio 改变默认值只影响之后新建的记录,已存在的记录不会被回写更新。
在技术定制中使用 Python
如果你需要更精细的控制(例如基于运行时信息的逻辑),应在 Python 模型字段定义中设置默认。这样可以实现静态值、lambda 以及基于方法的动态默认,是开发场景下的首选。
下面示例展示在自定义模块中添加多种默认的常见写法(示意):
示例(简化说明):
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
# 静态布尔默认
x_requires_review = fields.Boolean(
string='需要审核',
default=False,
)
# 静态选择默认
x_delivery_preference = fields.Selection(
[('standard', '普通'), ('express', '加急')],
string='配送偏好',
default='standard',
)
# 基于方法的动态默认
def _default_note(self):
return self.env['ir.config_parameter'].sudo().get_param(
'sale.default_note', default=''
)
x_internal_note = fields.Text(
string='内部备注',
default=_default_note,
)
这种模式符合 Odoo 的 Python 字段约定,方法型默认在逻辑比单个 lambda 更复杂时尤其有用。它适用于所有字段类型。
以编程方式创建或更新 ir.default 记录
你也可以通过 XML-RPC 或在模块的数据文件中创建/更新 ir.default。这在你想把默认配置随模块一起发布并在安装时应用时很有用。ir.default 接受模型名、字段名、值,以及可选的公司或用户范围参数。
这种方式在日常开发中不算常见,但在构建可安装模块并需随安装初始化合理默认配置时会用到。
默认值的最佳实践
为必填字段设定默认值
如果字段被设为必填,尽量给出合理的默认值以降低使用阻力,避免用户在新建时因为忘填必填项而无法保存。将 required=True 与实用的默认值结合是一种好习惯。
用 lambda 处理日期默认
不要把具体日期写死为默认值。应使用 lambda self: fields.Date.today(),以确保默认总是创建时的当天日期。写死的日期在代码一经部署后就会很快失效。
让默认逻辑保持轻量
默认函数会在每次打开新表单时运行,因此应避免在默认方法里进行大量数据库查询、调用外部接口或重计算。若逻辑复杂,考虑改用 onchange 或由其他字段触发的 compute 字段来处理。
为导航流使用上下文默认
在自定义动作或按钮打开新表单时,优先通过 action context 传入 default_field_name,而不是仅依赖模型级静态默认。这与 Odoo 原生按钮的工作方式一致,也能让你的自定义与框架约定保持一致。
用多账号测试默认行为
引用 self.env.user 或 self.env.company 的动态默认会随登录用户或公司不同而表现不同。务必用至少两个不同账号测试,若是多公司环境也要用不同公司配置验证。管理员下可正常的默认在普通用户下可能表现异常。
常见错误与注意事项
避免用可变对象作默认值
经典的 Python 错误在 Odoo 中同样适用:不要写 default=[] 或 default={},这样会在所有实例间共享同一对象,导致数据在记录间泄露。应使用 lambda,例如 default=lambda self: [],以便每次创建记录时生成新的对象。
默认值不会触发 onchange
为字段设默认值不会触发相应的 onchange 方法。也就是说,默认被预填但不会引发那些 onchange 会产生的连锁更新。如果你希望在初始化时也执行这些逻辑,需要在自定义的 default_get 中显式调用或通过其他方式处理相关逻辑。
ir.default 与模型定义冲突时的表现
如果同一字段既在 Python 中定义了默认,又通过 Studio 或 ir.default 设置了默认,Odoo 会按优先级选取值:ir.default 会覆盖模型级默认。这是调试默认值异常时常见的混淆来源,尤其在有人用 Studio 修改后悄然覆盖了代码中的设置。
不要把有默认值的字段当成必填的替代品
有默认值并不代表字段被强制填写。用户可以清空该字段并保存为空。如果你确实需要该字段始终有值,应同时设置 required=True。
避免硬编码用户或公司 ID
像 default=1 这种直接用数据库 ID 引用用户或公司很脆弱,在不同环境(开发、测试、生产)中同一记录很可能有不同的 ID,会导致默认失效或指向错误对象。请用动态引用,例如 lambda self: self.env.company.id 或 lambda self: self.env.ref('module.xml_id').id。
结语
默认值虽小,却是 Odoo 数据模型中非常高效的功能。它能减少重复输入、引导用户做出一致选择,让表单在打开时就更好用。不论是用 Studio 做快速的无代码调整,还是在 Python 模块里做技术性定制,理解默认值的工作方式都能帮助你构建更稳健的 Odoo 应用。
需要记住的要点:默认只在记录创建时计算,不会持续生效;默认不会触发 onchange;多个默认来源有明确的优先级;对于列表或字典等可变对象,务必用 lambda 生成新实例。
把默认值设置好往往能把一个让人头疼的表单,变成一个顺手的工具。这个小投入每天都会带来明显的效率回报。
在 Dasolo,我们帮助企业实现、定制并优化 Odoo 以契合特定业务流程。如果你需要配置字段默认、创建自定义字段或设计一套真正适合团队的数据模型,我们可以提供专业支持。 联系我们 让我们聊聊你的 Odoo 实施需求。