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

如何让Django表单选项依赖上一步表单提交的值?

实现步骤

1. 调整表单定义(forms.py)

把需要动态选项的字段改为ChoiceField,初始留空选项,后续在视图中动态赋值:

from django import forms

class CustomerAccountCreationForm(forms.Form):
    company_name = forms.CharField(max_length=100, label="公司名称")
    city = forms.CharField(max_length=100, label="公司所在城市")
    state = forms.CharField(max_length=100, label="公司所在州/省份")
    # 补充create_records函数需要的字段
    username = forms.CharField(max_length=100, label="API用户名")
    password = forms.CharField(max_length=100, label="API密码", widget=forms.PasswordInput)
    is_sandbox = forms.BooleanField(required=False, label="是否使用沙箱环境?")

class CustomerWORequiredFieldsForm(forms.Form):
    company_level_login = forms.BooleanField(required=False, label="是否使用公司级登录?")
    is_closed_on_completion = forms.BooleanField(required=False, label="工单完成后自动关闭?")
    # 改为ChoiceField,初始选项为空,后续动态赋值
    field_mapping = forms.ChoiceField(label="字段映射", choices=[])

2. 修改向导视图(views.py)

在get_form方法中,第一步提交后保存数据源ID到Session,第二步从数据库读取data_dict并动态设置表单选项:

from server.companies.models import Company
from server.data_sources.models import DataDictionary, DataSource
from django.shortcuts import render
from formtools.wizard.views import SessionWizardView
import json
import logging

from server.data_sources import ds
from server.data_sources.models import SOURCE

logger = logging.getLogger("server." + __name__)

def create_records(data):
    if not data or data == {}:
        return
    name = data.get("company_name")
    is_sandbox = data.get("is_sandbox")
    city = data.get("city")
    state = data.get("state")
    username = data.get("username")
    password = data.get("password")

    data_source = DataSource.objects.create(
        name=name,
        source_type=SOURCE,
    )
    ds.login(data_source, username, password)

    company = Company.objects.create(
        name=name,
        data_source=data_source,
    )

    return company

class Wizard(SessionWizardView):
    template_name = "wizard.html"

    def done(self, form_list, **kwargs):
        # 清理Session中的临时数据
        self.request.session.pop('data_source_id', None)
        return render(
            self.request,
            "done.html",
            {"form_data": [form.cleaned_data for form in form_list]},
        )

    def get_form_step_data(self, form):
        return form.data

    def get_form(self, step=None, data=None, files=None):
        form = super().get_form(step, data, files)
        if step is None:
            step = self.steps.current

        if step == "0":
            if form.is_valid():
                step_zero_data = form.cleaned_data
                company = create_records(step_zero_data)
                source = company.data_source
        
                data_dict = {}
                for field in ds.select(company, "DATADICT", ["dd_dbf", "dd_name", "dd_desc"]):
                    table = field["dd_dbf"]
                    field_name = field["dd_name"]
                    if table not in data_dict:
                        data_dict[table] = []
                    data_dict[table].append(field_name)

                # 保存数据字典到数据库
                data_dict_json = json.dumps(data_dict, indent=4)
                existing_data_dict = DataDictionary.objects.filter(data_source=source).first()
                if existing_data_dict:
                    existing_data_dict.data = data_dict_json
                    existing_data_dict.save()
                else:
                    DataDictionary.objects.create(data_source=source, data=data_dict_json)
                
                # 将数据源ID存入Session,供第二步使用
                self.request.session['data_source_id'] = source.id

        elif step == "1":
            # 从Session获取数据源ID
            source_id = self.request.session.get('data_source_id')
            if not source_id:
                # 若未完成第一步,强制跳转回第一步
                return self.render_goto_step('0')
            
            # 从数据库读取数据字典
            data_dict_obj = DataDictionary.objects.filter(data_source_id=source_id).first()
            if data_dict_obj:
                data_dict = json.loads(data_dict_obj.data)
                # 转换为ChoiceField需要的格式:(值, 显示标签)
                choices = []
                for table, fields in data_dict.items():
                    for field in fields:
                        choice_value = f"{table}.{field}"
                        choice_label = f"{table} - {field}"
                        choices.append((choice_value, choice_label))
                # 动态设置字段选项
                form.fields['field_mapping'].choices = choices

        return form

3. 修正URL配置(urls.py)

修正视图类名的笔误(原ContactWizard改为Wizard):

from django.conf.urls import url
from .forms import CustomerAccountCreationForm, CustomerWORequiredFieldsForm
from .views import Wizard

customer_creation_wizards_forms = [
    CustomerAccountCreationForm,
    CustomerWORequiredFieldsForm,
]

urlpatterns = [
    url(
        r"^customers/",
        Wizard.as_view(customer_creation_wizards_forms),
    ),
]

关键说明

  • 第一步提交后,将数据源ID存入Session,确保第二步能关联到对应的data_dict
  • 第二步从数据库读取已保存的data_dict,转换为ChoiceField要求的选项格式后赋值给表单字段
  • 若用户未完成第一步直接访问第二步,会强制跳转回第一步,避免无数据的情况
  • 表单流程完成后清理Session中的临时数据,避免残留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 02:54:24