如何阻止Django Formset保存特定的部分填写表单
Django Formset 过滤仅填充Activity的空表单保存问题
方法一:表单级验证(推荐)
在WeeksForm中添加clean方法,直接在表单层面做校验,确保只有activity但无星期数据的表单无法通过验证:
class WeeksForm(forms.ModelForm): monday = forms.DecimalField(required=False) tuesday = forms.DecimalField(required=False) wednesday = forms.DecimalField(required=False) thursday = forms.DecimalField(required=False) friday = forms.DecimalField(required=False) saturday = forms.DecimalField(required=False) sunday = forms.DecimalField(required=False) class Meta: model = Weeks fields = ('activity', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday') def clean(self): cleaned_data = super().clean() # 定义所有星期字段的名称列表 day_fields = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] # 检查是否有任意一个星期字段有值 has_day_data = any(cleaned_data.get(day) is not None for day in day_fields) # 如果activity已填写,但所有星期字段为空,抛出验证错误 if cleaned_data.get('activity') and not has_day_data: raise forms.ValidationError("请至少填写一个星期的数值") return cleaned_data
当用户提交仅含activity的表单时,formset.is_valid()会返回False,页面会显示对应的错误提示,阻止这类表单被保存。
方法二:视图层标记无效表单为删除状态
如果希望不显示错误提示,直接忽略这类表单,可以在视图中遍历表单,将符合条件的表单标记为删除(利用formset的can_delete特性):
if request.method == 'POST': formset = WeeksFormset(request.POST) if formset.is_valid(): day_fields = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] for form in formset.forms: # 检查当前表单是否仅填写了activity,星期字段全为空 has_day_data = any(getattr(form.instance, day) is not None for day in day_fields) if form.instance.activity and not has_day_data: # 标记为删除,save()时会跳过该表单 form.cleaned_data['DELETE'] = True else: form.instance.user = request.user # 保存有效表单 formset.save() return HttpResponseRedirect(reverse("time"))
方法三:表单集级验证
自定义表单集基类,在表单集层面统一处理校验逻辑:
from django.forms import BaseModelFormSet class BaseWeeksFormSet(BaseModelFormSet): def clean(self): super().clean() day_fields = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'] for form in self.forms: # 跳过本身就无效的表单 if not form.is_valid(): continue has_day_data = any(form.cleaned_data.get(day) is not None for day in day_fields) if form.cleaned_data.get('activity') and not has_day_data: form.add_error(None, "请至少填写一个星期的数值") # 用自定义的表单集基类生成formset WeeksFormset = modelformset_factory(Weeks, form=WeeksForm, formset=BaseWeeksFormSet, extra=10, can_delete=True)
这种方式和方法一类似,只是把校验逻辑放在了表单集层面,适合需要统一处理多个表单校验规则的场景。
内容的提问来源于stack exchange,提问作者Carlos S. C.
相关产品推荐
相关产品推荐

