Django表单未验证模型唯一约束直接返回数据库约束校验错误问题
核心问题定位
你的自定义校验逻辑完全未执行,根因是2处低级错误:
__init__、clean方法缩进错误,被写在了Meta内部类的范围内,不属于表单类,因此不会被Django调用- 自定义的表单
__init__要求传入username作为第一个参数,但视图层实例化表单时未传递该参数,即使方法缩进正确也无法正常执行
修复步骤
第一步:修正form.py的缩进和逻辑错误
from django import forms from . models import Semana class FormularioSemana(forms.ModelForm): class Meta: model = Semana fields = '__all__' widgets = { 'lunes_inicio': forms.TimeInput(attrs={'type': 'time'}), 'lunes_fin': forms.TimeInput(attrs={'type': 'time'}), 'martes_inicio': forms.TimeInput(attrs={'type': 'time'}), 'martes_fin': forms.TimeInput(attrs={'type': 'time'}), 'miercoles_inicio': forms.TimeInput(attrs={'type': 'time'}), 'miercoles_fin': forms.TimeInput(attrs={'type': 'time'}), 'jueves_inicio': forms.TimeInput(attrs={'type': 'time'}), 'jueves_fin': forms.TimeInput(attrs={'type': 'time'}), 'viernes_inicio': forms.TimeInput(attrs={'type': 'time'}), 'viernes_fin': forms.TimeInput(attrs={'type': 'time'}), 'sabado_inicio': forms.TimeInput(attrs={'type': 'time'}), 'sabado_fin': forms.TimeInput(attrs={'type': 'time'}), 'domingo_inicio': forms.TimeInput(attrs={'type': 'time'}), 'domingo_fin': forms.TimeInput(attrs={'type': 'time'}), } # 注意:__init__要和Meta同级,不要缩进在Meta里面 def __init__(self, username, *args, **kwargs): super(FormularioSemana, self).__init__(*args, **kwargs) self.instance.username = username if not username.is_staff: # 修复变量错误:这里没有request变量,直接用传入的username self.fields['nombre'].queryset = Semana.stem.filter(username = username) # clean方法同样要和Meta同级 def clean(self, *args, **kwargs): cleaned_data = super().clean(*args, **kwargs) nombre = cleaned_data['nombre'] username = self.instance.username duplicates = Semana.stem.filter( nombre=nombre, username=username ) if self.instance.pk: duplicates = duplicates.exclude(pk=self.instance.pk) if duplicates.exists(): raise forms.ValidationError('El nombre de la semana existe!') # 必须返回cleaned_data return cleaned_data
第二步:修正views.py的表单实例化逻辑
def index(request): if request.method == 'POST': # 第一个参数传入request.user,匹配表单自定义__init__的要求 form = FormularioSemana(request.user, request.POST) if form.is_valid(): # 表单已经给instance赋值了username,不需要再手动赋值 form.save() all_items = Semana.stem.filter(username = request.user) semana = FormularioSemana(request.user) messages.success(request, ('New item added...')) else: # 校验失败的情况要返回带错误的表单,不能直接new一个新表单 semana = form all_items = Semana.stem.filter(username = request.user) return render (request, 'semana.html', {'form':semana, 'all_items':all_items}) else: # GET请求实例化也要传username semana = FormularioSemana(request.user) all_items = Semana.stem.filter(username = request.user) return render(request, 'semana.html', {'form':semana, 'all_items':all_items})
额外注意点
你原来的视图校验失败后直接new了一个空表单返回,会导致前端看不到表单的错误提示,上面的修复代码也同步处理了这个问题。
内容的提问来源于stack exchange,提问作者DSTdan
相关产品推荐
相关产品推荐

