Django动态表单集为空时仍可提交 如何实现非空校验阻止提交
问题根源
- 视图逻辑错误:原代码只要患者主表单校验通过就会直接保存患者数据并跳转,完全不阻塞诊断表单集校验失败的场景,就算诊断信息不符合要求也会提交成功,用户自然看不到校验提示。
- GET请求中主表单未实例化:原GET方法里直接把
PatientForm类传给模板,没有实例化,会导致前端渲染的表单缺少浏览器端自带的必填校验属性。 - 缺少表单集自定义校验:仅靠默认的
min_num校验不足以覆盖用户新增行后全部留空、或者删除所有有效行的场景。
修复方案
1. 修正forms.py,增加表单集全局校验
新增自定义表单集基类,强制校验至少存在一条有效诊断数据:
from django.forms import BaseInlineFormSet, forms class PatientForm(ModelForm): class Meta: model = Patient fields = ['age'] class BaseDiagnosisFormSet(BaseInlineFormSet): def clean(self): super().clean() valid_count = 0 for form in self.forms: # 跳过标记为删除的行 if self.can_delete and self._should_delete_form(form): continue # 统计填写了诊断信息的有效行 if form.cleaned_data and form.cleaned_data.get('diag_name'): valid_count += 1 if valid_count < 1: raise forms.ValidationError("至少需要填写一条有效的诊断信息") DiagnosisFormSet = inlineformset_factory( Patient, Diagnosis, formset=BaseDiagnosisFormSet, fields=("diag_name", ), extra=0, min_num=1, validate_min=True, can_delete=True )
2. 修正views.py,调整校验和保存逻辑
必须主表单和表单集同时校验通过才执行保存操作,校验失败时返回页面展示错误信息:
class PatientAddView(LoginRequiredMixin,TemplateView): model = Patient template_name = "../templates/patient/add.html" def get(self, *args, **kwargs): # 实例化表单而非直接传类 patient_form = PatientForm() diagnosis_formset = DiagnosisFormSet(queryset=Diagnosis.objects.none()) return self.render_to_response({ 'diagnosis_formset': diagnosis_formset, 'patient_form': patient_form }) def post(self, *args, **kwargs): form = PatientForm(data=self.request.POST) diagnosis_formset = DiagnosisFormSet(data=self.request.POST) # 两个表单同时校验通过才执行保存 if form.is_valid() and diagnosis_formset.is_valid(): patient_instance = form.save(commit=False) patient_instance.user = self.request.user patient_instance.save() diag_instances = diagnosis_formset.save(commit=False) for diag in diag_instances: diag.patient = patient_instance diag.save() # 仅保存成功后跳转 return redirect(reverse( 'patient:treatment_detail', kwargs={"patient_id": patient_instance.patient_id} )) # 校验失败返回带错误信息的表单页 return self.render_to_response({ 'diagnosis_formset': diagnosis_formset, 'patient_form': form })
3. 前端适配注意
- 动态新增formset行时,必须正确更新
id_form-TOTAL_FORMS等表单集管理字段的值,否则新增行不会被后端识别、不会触发校验。 - 模板中需要渲染
diagnosis_formset.non_form_errors,才能显示上面自定义的全局校验提示。
内容的提问来源于stack exchange,提问作者RobMcC
相关产品推荐
相关产品推荐

