如何动态调整Odoo的Selection字段选项?求非弃用方案
动态设置Selection选项仅显示'i',求非弃用的动态限制方案
我尝试通过lambda调用自定义方法动态设置report_type字段的Selection选项,但最终仅显示'i'选项。之前找到的domain方案已经被弃用,无法生效。job_id关联资产持有人提交的服务请求,现在想找非弃用的方法来动态限制用户可选的选项,比如临时记录(transient record)或者其他可行方案。
现有代码
job_id = fields.Many2one('inw_asset.job_orders', string='Service request', required=True, store=True) owner_id = fields.Many2one('res.users', string='Asset Owner', required=True, default=lambda self: self.env.user, readonly=True, store=True) person_in_charge = fields.Many2one('res.users', string='Engineer assigned', required=True, store=True) report_type = fields.Selection(selection=lambda self: self.get_report_type_list(), required=True, default='i') def get_report_type_list(self): user = self.env.user if self.env.user.has_group('inw_asset.administrator'): return [ ('i', 'Information'), ('p', 'Progress'), ('r', 'Completion Report'), ('d', 'Delayed') ] elif self.env.user == self.owner_id: return [ ('i', 'Information'), ('r', 'Completion Report'), ] elif self.env.user == self.person_in_charge: # 修正原代码语法错误:添加冒号 return [ ('i', 'Information'), ('p', 'Progress'), ('d', 'Delayed') ] else: return [ ('i', 'Information') ]
问题根源
- lambda执行时机错误:Selection字段的
selection参数中的lambda是在模型加载时执行,此时self是空记录集,无法获取当前编辑记录的owner_id和person_in_charge值,导致非管理员用户全部进入else分支,只显示'i'选项。 - 语法错误:第三个
elif语句末尾缺失冒号,会触发代码执行异常,直接进入else分支。
可行解决方案
方案1:计算字段+视图Domain(Odoo 14+官方推荐)
这是最简洁的后端驱动方案,避开了selection参数的执行时机问题:
- 先定义全量选项的
report_type字段:
report_type = fields.Selection([ ('i', 'Information'), ('p', 'Progress'), ('r', 'Completion Report'), ('d', 'Delayed') ], required=True, default='i')
- 添加计算字段返回当前用户允许的选项值:
allowed_report_types = fields.Char(compute='_compute_allowed_report_types', store=False) def _compute_allowed_report_types(self): for rec in self: user = self.env.user if user.has_group('inw_asset.administrator'): allowed = ['i', 'p', 'r', 'd'] elif user == rec.owner_id: allowed = ['i', 'r'] elif user == rec.person_in_charge: allowed = ['i', 'p', 'd'] else: allowed = ['i'] rec.allowed_report_types = ','.join(allowed)
- 在表单视图中给
report_type添加Domain限制:
<field name="report_type" domain="[('value', 'in', allowed_report_types.split(','))]"/>
方案2:临时记录(Transient Record)弹窗选择
适合需要更复杂交互的场景,通过弹窗动态生成选项:
- 创建临时模型:
from odoo import models, fields, api class ReportTypeSelectionWizard(models.TransientModel): _name = 'report.type.selection.wizard' _description = 'Dynamic Report Type Selection' report_type = fields.Selection([], required=True) main_record_id = fields.Many2one('your.main.model.name') # 替换为你的主模型名称 @api.model def default_get(self, fields): res = super().default_get(fields) main_record = self.env['your.main.model.name'].browse(self._context.get('active_id')) user = self.env.user # 动态生成选项 if user.has_group('inw_asset.administrator'): selection = [ ('i', 'Information'), ('p', 'Progress'), ('r', 'Completion Report'), ('d', 'Delayed') ] elif user == main_record.owner_id: selection = [('i', 'Information'), ('r', 'Completion Report')] elif user == main_record.person_in_charge: selection = [('i', 'Information'), ('p', 'Progress'), ('d', 'Delayed')] else: selection = [('i', 'Information')] self._fields['report_type'].selection = selection res['main_record_id'] = main_record.id return res def action_confirm_selection(self): self.main_record_id.write({'report_type': self.report_type}) return {'type': 'ir.actions.act_window_close'}
- 配置临时模型的动作和表单视图(常规配置即可),然后在主模型视图中添加触发按钮:
<button name="%(report.type.selection.wizard_action)d" type="action" string="Select Report Type" context="{'active_id': active_id}"/>
方案3:前端JavaScript动态控制选项
无需修改后端逻辑,通过前端隐藏不允许的选项:
- 创建JS文件:
odoo.define('your_module.dynamic_report_type', function(require) { 'use strict'; var fieldRegistry = require('web.field_registry'); var SelectionField = require('web.basic_fields').SelectionField; var DynamicReportType = SelectionField.extend({ _renderEdit: function() { this._super.apply(this, arguments); var record = this.recordData; var userId = this.session.uid; let allowedTypes = []; // 判断当前用户允许的选项 if (this.session.user_has_group('inw_asset.administrator')) { allowedTypes = ['i', 'p', 'r', 'd']; } else if (record.owner_id && record.owner_id[0] === userId) { allowedTypes = ['i', 'r']; } else if (record.person_in_charge && record.person_in_charge[0] === userId) { allowedTypes = ['i', 'p', 'd']; } else { allowedTypes = ['i']; } // 隐藏不允许的选项 this.$el.find('option').each(function() { const val = $(this).val(); if (!allowedTypes.includes(val)) { $(this).hide(); } }); }, }); fieldRegistry.add('dynamic_report_type', DynamicReportType); return DynamicReportType; });
- 在视图中将
report_type的widget指定为自定义组件:
<field name="report_type" widget="dynamic_report_type"/>
内容的提问来源于stack exchange,提问作者Magician
相关产品推荐
相关产品推荐

