Django:如何用POST提交的前置表单数据预填充FormView的ModelForm?
我正在开发一款会议纪要创建工具,需要将用户通过POST提交的前置表单数据,预填充到Django FormView对应的ModelForm中。搭建了简化项目复现问题:前置表单(MyForm)仅包含president和secretary字段,而ModelForm(MyMinuteModelForm)包含body字段,我需要利用前置表单提交的信息动态生成body字段的初始值,但重写get_initial()方法后无法成功填充body字段,president和secretary字段可自动填充,且打印get_initial中的initial为空,已尝试重写get_initial()方法但未奏效。
前置表单代码
from django import forms from core.models import MinuteModel class MyForm(forms.Form): president = forms.CharField(widget=forms.TextInput()) secretary = forms.CharField(widget=forms.TextInput())
模型代码
class MinuteModel(models.Model): president = models.CharField(max_length=120) secretary = models.CharField(max_length=120) body = models.CharField(max_length=1000)
会议纪要表单代码
class MyMinuteModelForm(forms.ModelForm): class Meta: model = MinuteModel fields = "__all__"
FormView代码
class MyFormView(FormView): form_class = MyMinuteModelForm template_name = "core/creation.html" def get_initial(self): initial = super(MyFormView, self).get_initial() initial['body'] = "asdasd" return initial
解决办法
1. 核心问题分析
get_initial()仅在GET请求初始化表单时生效,若你的请求中已携带president/secretary的参数(比如前置表单跳转时的GET参数),Django会优先使用请求参数而非initial值;另外super().get_initial()默认返回空字典是正常现象,只需在其基础上添加字段值即可。body未填充的关键原因是前置数据未正确传递到MyFormView,或请求逻辑覆盖了初始值。
2. 正确传递前置数据并生成body初始值
方式一:通过Session传递数据
先处理前置表单的View,将验证通过的数据存入Session:
class PreFormView(FormView): form_class = MyForm template_name = "core/pre_form.html" success_url = reverse_lazy("minute_form") def form_valid(self, form): # 存储前置数据到Session self.request.session['president'] = form.cleaned_data['president'] self.request.session['secretary'] = form.cleaned_data['secretary'] return super().form_valid(form)
修改MyFormView,从Session取数据生成初始值:
class MyFormView(FormView): form_class = MyMinuteModelForm template_name = "core/creation.html" def get_initial(self): initial = super().get_initial() # 从Session获取前置数据 president = self.request.session.get('president', '') secretary = self.request.session.get('secretary', '') # 动态生成body初始内容 initial['body'] = f"会议主持:{president}\n记录人:{secretary}" # 显式填充president和secretary字段 initial['president'] = president initial['secretary'] = secretary return initial def form_valid(self, form): # 提交后清理Session临时数据 for key in ['president', 'secretary']: if key in self.request.session: del self.request.session[key] return super().form_valid(form)
方式二:通过GET参数传递数据
前置表单验证通过后,将数据拼接到跳转URL的GET参数中:
class PreFormView(FormView): form_class = MyForm template_name = "core/pre_form.html" def get_success_url(self): president = self.form.cleaned_data['president'] secretary = self.form.cleaned_data['secretary'] # 拼接GET参数到跳转URL return f"{reverse_lazy('minute_form')}?president={president}&secretary={secretary}"
修改MyFormView的get_initial():
class MyFormView(FormView): form_class = MyMinuteModelForm template_name = "core/creation.html" def get_initial(self): initial = super().get_initial() # 从GET参数中提取前置数据 president = self.request.GET.get('president', '') secretary = self.request.GET.get('secretary', '') # 动态生成body初始内容 initial['body'] = f"会议主持:{president}\n记录人:{secretary}" # 显式填充字段 initial['president'] = president initial['secretary'] = secretary return initial
3. 模板渲染验证
确保模板core/creation.html正确渲染表单,不要手动给body字段设置value属性,避免覆盖初始值:
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form>
内容的提问来源于stack exchange,提问作者herrmartins

