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

Odoo 16向导中基于模板动态生成字段的实现方法问询

实现Odoo 16 向导动态字段展示

1. 定义向导模型(TransientModel)

创建基于TransientModel的向导模型,包含关联模板的Many2one字段,以及用于存储动态字段值的JSON字段:

from odoo import models, fields, api

class DynamicFieldWizard(models.TransientModel):
    _name = 'dynamic.field.wizard'
    _description = 'Dynamic Field Wizard'

    template_ids = fields.Many2one('your.template.model', string='Template', required=True)
    dynamic_values = fields.Json(string='Dynamic Values', default={})

    @api.onchange('template_ids')
    def _onchange_template_ids(self):
        # 切换模板时清空之前的动态值
        self.dynamic_values = {}

替换your.template.model为实际的模板模型名称,确保该模型包含variables_id的One2many字段(关联变量模型)。

2. 设计向导视图

编写form视图,添加模板选择字段,预留动态字段容器,并引入自定义JS脚本:

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <record id="dynamic_field_wizard_form" model="ir.ui.view">
        <field name="name">dynamic.field.wizard.form</field>
        <field name="model">dynamic.field.wizard</field>
        <field name="arch" type="xml">
            <form string="Dynamic Field Wizard">
                <sheet>
                    <group>
                        <field name="template_ids" required="1" />
                        <!-- 动态字段容器 -->
                        <div id="dynamic_fields_container" class="mt-3">
                            <!-- 动态生成的字段将插入此处 -->
                        </div>
                        <!-- 隐藏字段存储动态值 -->
                        <field name="dynamic_values" invisible="1" />
                    </group>
                </sheet>
                <footer>
                    <button name="action_confirm" type="object" string="Confirm" class="btn-primary" />
                    <button string="Cancel" class="btn-secondary" special="cancel" />
                </footer>
            </form>
        </field>
    </record>

    <!-- 注册向导启动动作 -->
    <record id="action_dynamic_field_wizard" model="ir.actions.act_window">
        <field name="name">Dynamic Field Wizard</field>
        <field name="res_model">dynamic.field.wizard</field>
        <field name="view_mode">form</field>
        <field name="target">new</field>
    </record>
</odoo>

3. 编写前端JS逻辑

创建JS文件,监听template_ids字段变化,动态生成对应数量的输入字段:

odoo.define('dynamic_field_wizard.dynamic_fields', function (require) {
    "use strict";

    var core = require('web.core');
    var FormView = require('web.FormView');
    var QWeb = core.qweb;

    FormView.include({
        on_loaded: function () {
            this._super.apply(this, arguments);
            var self = this;
            var templateField = this.$el.find('div[name="template_ids"]');
            
            // 初始加载时若已有选中模板,直接生成字段
            if (this.datarecord.template_ids) {
                self._generateDynamicFields(this.datarecord.template_ids[0]);
            }

            // 监听模板选择变化
            templateField.on('change', function () {
                var templateId = templateField.find('input').val();
                if (templateId) {
                    self._generateDynamicFields(templateId);
                } else {
                    $('#dynamic_fields_container').empty();
                    self.datarecord.dynamic_values = {};
                }
            });
        },

        _generateDynamicFields: function (templateId) {
            var self = this;
            // 调用后端获取模板关联的变量数据
            this._rpc({
                model: 'your.template.model',
                method: 'read',
                args: [[templateId], ['variables_id']],
            }).then(function (templates) {
                var variables = templates[0].variables_id;
                var container = $('#dynamic_fields_container');
                container.empty();

                // 遍历变量生成输入字段
                variables.forEach(function (variable) {
                    var variableId = variable[0];
                    var variableName = variable[1];
                    // 渲染动态字段模板
                    var fieldHtml = QWeb.render('DynamicFieldTemplate', {
                        variable_id: variableId,
                        variable_name: variableName,
                        current_value: self.datarecord.dynamic_values[variableName] || ""
                    });
                    container.append(fieldHtml);

                    // 绑定输入值到dynamic_values字段
                    container.find('#dynamic_field_' + variableId).on('input', function () {
                        var value = $(this).val();
                        self.datarecord.dynamic_values[variableName] = value;
                        // 更新隐藏字段的JSON值
                        self.$el.find('input[name="dynamic_values"]').val(JSON.stringify(self.datarecord.dynamic_values));
                    });
                });
            });
        }
    });

    // 定义动态字段的QWeb模板
    core.qweb.add_template('DynamicFieldTemplate',
        '<div class="form-group">' +
            '<label class="col-form-label" for="dynamic_field_{{ variable_id }}">{{ variable_name }}</label>' +
            '<input type="text" id="dynamic_field_{{ variable_id }}" class="form-control" value="{{ current_value }}"/>' +
        '</div>'
    );

    return {};
});

替换your.template.model为实际模板模型名称,若变量模型包含字段类型(如选择框、日期),可扩展模板生成对应控件。

4. 注册JS脚本

在模块的__manifest__.py中引入JS文件:

{
    # ... 其他模块配置
    'assets': {
        'web.assets_backend': [
            'your_module_name/static/src/js/dynamic_fields.js',
        ],
    },
}

5. 处理确认动作(可选)

若需在确认时处理动态字段值,在向导模型中添加方法:

def action_confirm(self):
    self.ensure_one()
    # 读取dynamic_values中的数据执行业务逻辑
    for variable_name, value in self.dynamic_values.items():
        # 示例:打印变量名和对应值
        print(f"Variable: {variable_name}, Value: {value}")
    return {'type': 'ir.actions.act_window_close'}

核心逻辑说明

  • 动态字段值通过JSON字段dynamic_values存储,避免后端动态创建字段的复杂度
  • 前端通过RPC拉取模板关联的变量数据,动态渲染表单控件
  • 可根据变量类型扩展生成不同的输入控件(如下拉框、日期选择器)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 22:45:21