如何让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
相关产品推荐
相关产品推荐

