如何在Odoo 16中根据字段值设置表单所有字段为只读?
解决方案
针对Odoo 16中根据字段值批量设置表单所有字段只读的需求,给你几个更高效的方案:
方案1:利用表单editable属性的动态控制(最简便)
Odoo的表单视图支持通过attrs控制editable属性,直接实现整个表单的只读/可编辑切换,无需逐个处理字段:
<form attrs="{'editable': [('my_field', '=', False)]}"> <!-- 原表单内的所有字段内容 --> </form>
当my_field为True时,表单会自动切换为只读模式,所有字段不可编辑,同时编辑按钮也会被隐藏,完全符合实时控制的需求,而且兼容后续新增的字段。
方案2:改进XPath批量合并字段attrs
你之前的XPath写法会直接覆盖字段原有的attrs规则,导致部分场景失效。可以通过eval合并原有规则与新的只读条件,避免冲突:
<xpath expr="//form//field" position="attributes"> <attribute name="attrs" eval="dict(record.attrs or {}, readonly=[('my_field', '=', True)])"/> </xpath>
这个写法会保留字段原本的attrs配置,仅新增基于my_field的只读规则,适用于需要保留字段原有属性的场景。
方案3:自定义JS表单组件(最灵活)
如果需要更复杂的交互控制,可以通过自定义JS组件监听字段变化,动态设置所有字段的只读状态:
- 新增JS文件(如
static/src/js/custom_form.js):
odoo.define('my_module.custom_form', function (require) { 'use strict'; const FormView = require('web.FormView'); const viewRegistry = require('web.view_registry'); const CustomReadOnlyForm = FormView.extend({ // 初始化时更新只读状态 init: function () { this._super.apply(this, arguments); this.on('record_loaded', this, this._updateReadonlyState); }, // 字段变化时更新状态 _onFieldChanged: function (ev) { this._super.apply(this, arguments); if (ev.data.changes.my_field) { this._updateReadonlyState(); } }, // 核心逻辑:设置所有字段只读状态 _updateReadonlyState: function () { const recordData = this.model.get(this.handle).data; const isReadonly = recordData.my_field; // 控制所有可编辑元素 this.$el.find('.o_field_widget:not(.o_readonly_modifier)').toggleClass('o_readonly_modifier', isReadonly); this.$el.find('input, select, textarea').prop('readonly', isReadonly); // 控制编辑按钮显示 this.$el.find('.o_form_button_edit').toggle(!isReadonly); }, }); viewRegistry.add('custom_readonly_form', CustomReadOnlyForm); });
- 在视图中指定使用该组件:
<form js_class="custom_readonly_form"> <!-- 原表单内容 --> </form>
这种方式完全自定义控制逻辑,适配各种复杂场景,且自动兼容后续新增的字段。
内容的提问来源于stack exchange,提问作者forvas
相关产品推荐
相关产品推荐

