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

如何动态调整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')
        ]

问题根源

  1. lambda执行时机错误:Selection字段的selection参数中的lambda是在模型加载时执行,此时self是空记录集,无法获取当前编辑记录的owner_id和person_in_charge值,导致非管理员用户全部进入else分支,只显示'i'选项。
  2. 语法错误:第三个elif语句末尾缺失冒号,会触发代码执行异常,直接进入else分支。

可行解决方案

方案1:计算字段+视图Domain(Odoo 14+官方推荐)

这是最简洁的后端驱动方案,避开了selection参数的执行时机问题:

  1. 先定义全量选项的report_type字段:
report_type = fields.Selection([
    ('i', 'Information'),
    ('p', 'Progress'),
    ('r', 'Completion Report'),
    ('d', 'Delayed')
], required=True, default='i')
  1. 添加计算字段返回当前用户允许的选项值:
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)
  1. 在表单视图中给report_type添加Domain限制:
<field name="report_type" domain="[('value', 'in', allowed_report_types.split(','))]"/>

方案2:临时记录(Transient Record)弹窗选择

适合需要更复杂交互的场景,通过弹窗动态生成选项:

  1. 创建临时模型:
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'}
  1. 配置临时模型的动作和表单视图(常规配置即可),然后在主模型视图中添加触发按钮:
<button name="%(report.type.selection.wizard_action)d" type="action" string="Select Report Type" context="{'active_id': active_id}"/>

方案3:前端JavaScript动态控制选项

无需修改后端逻辑,通过前端隐藏不允许的选项:

  1. 创建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;
});
  1. 在视图中将report_type的widget指定为自定义组件:
<field name="report_type" widget="dynamic_report_type"/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 00:44:50