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

Django中如何从模板调用表单方法实现动态表单?

问题分析与解决方案

核心问题

  1. 模板无法调用表单方法:Django Admin的change_form.html模板中,表单实例需通过adminform.form访问,而非直接form变量,原代码中form.get_schemas无法找到对应实例。
  2. 字段渲染方式错误:直接输出字段对象不会生成HTML输入框,需通过表单的字段引用渲染完整的表单控件(含标签、输入框)。
  3. 动态字段分组逻辑缺失:原get_schemas返回单个字段,未按Schema条目分组,不符合UI展示需求。

步骤1:修正表单方法与初始化逻辑

修改forms.py,完善Schema处理、新增索引获取方法,并添加表单提交后的字段值整合逻辑:

import json
from django import forms
from .models import MailTemplate, SCHEMA_DATA_TYPES

class MailTemplateForm(forms.ModelForm):
    class Meta:
        model = MailTemplate
        fields = ['name', 'tfile', 'schema']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 处理Schema为空的情况
        schema_data = self.instance.schema
        if schema_data:
            schema = json.loads(schema_data.strip())
            for i in range(len(schema)):
                # 添加name字段(只读)
                self.fields[f'schema_{i}_name'] = forms.CharField(
                    max_length=20, 
                    initial=schema[i]['name'],
                    label=f"字段名称 {i+1}"
                )
                self.fields[f'schema_{i}_name'].widget.attrs["readonly"] = True
                # 添加label字段
                self.fields[f'schema_{i}_label'] = forms.CharField(
                    max_length=20, 
                    required=True, 
                    initial=schema[i]['label'],
                    label=f"显示标签 {i+1}"
                )
                # 添加type字段
                self.fields[f'schema_{i}_type'] = forms.ChoiceField(
                    choices=SCHEMA_DATA_TYPES,
                    initial=schema[i]['type'],
                    label=f"数据类型 {i+1}"
                )
                # 添加format字段
                self.fields[f'schema_{i}_format'] = forms.CharField(
                    max_length=20, 
                    required=True, 
                    initial=schema[i]['format'],
                    label=f"格式 {i+1}"
                )

    def get_schema_indices(self):
        """返回Schema条目的索引范围,用于模板循环"""
        schema_data = self.instance.schema
        if schema_data:
            return range(len(json.loads(schema_data.strip())))
        return []

    def clean(self):
        """收集动态字段值,更新回Schema字段"""
        cleaned_data = super().clean()
        schema = []
        for i in self.get_schema_indices():
            schema.append({
                'name': cleaned_data.get(f'schema_{i}_name'),
                'label': cleaned_data.get(f'schema_{i}_label'),
                'type': int(cleaned_data.get(f'schema_{i}_type')),
                'format': cleaned_data.get(f'schema_{i}_format')
            })
        cleaned_data['schema'] = json.dumps(schema)
        return cleaned_data

步骤2:修正Admin模板的表单引用与字段渲染

修改mailtemplate_form.html,使用adminform.form访问表单实例,按Schema条目分组渲染字段:

{% extends "admin/change_form.html" %}

{% block after_field_sets %}
  {% if not add %}
    <div id="schema_head" style="margin: 15px 0;">
      <b>Schema 配置</b>
    </div>
    <div id="additional_fields">
      {% for i in adminform.form.get_schema_indices %}
        <div style="margin-bottom: 10px; padding: 10px; border: 1px solid #eee;">
          {% with name_field='schema_'|add:i|stringformat:"s"|add:'_name' %}
            <div style="display: inline-block; margin-right: 15px;">
              {{ adminform.form[name_field].label_tag }}
              {{ adminform.form[name_field] }}
            </div>
          {% endwith %}
          
          {% with label_field='schema_'|add:i|stringformat:"s"|add:'_label' %}
            <div style="display: inline-block; margin-right: 15px;">
              {{ adminform.form[label_field].label_tag }}
              {{ adminform.form[label_field] }}
            </div>
          {% endwith %}
          
          {% with type_field='schema_'|add:i|stringformat:"s"|add:'_type' %}
            <div style="display: inline-block; margin-right: 15px;">
              {{ adminform.form[type_field].label_tag }}
              {{ adminform.form[type_field] }}
            </div>
          {% endwith %}
          
          {% with format_field='schema_'|add:i|stringformat:"s"|add:'_format' %}
            <div style="display: inline-block;">
              {{ adminform.form[format_field].label_tag }}
              {{ adminform.form[format_field] }}
            </div>
          {% endwith %}
        </div>
      {% endfor %}
    </div>
  {% endif %}
{% endblock %}

模板说明

  • 使用adminform.form访问自定义表单实例,确保能调用get_schema_indices方法。
  • 通过with标签拼接动态字段名,使用adminform.form[field_name]渲染完整的表单控件(标签+输入框)。
  • 添加基础样式优化展示效果,可根据需求调整。

步骤3:验证与测试

  1. 重启Django服务,进入MailTemplate的编辑页面,确认Schema动态字段正常显示。
  2. 修改字段值后提交表单,检查数据库中schema字段的JSON值是否同步更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:15:34