Django表单校验失效未返回错误 非法slug提交时errors为空
Django表单校验无返回错误问题排查
问题现象
Django开发过程中出现表单校验异常:表单不符合校验规则时无任何错误信息返回。现有Tag模型包含name、slug两个字段,提交值为create的非法slug数据、且name字段为空时,预设的表单验证逻辑未正常触发。Shell环境测试时,传入{'slug': 'create'}参数实例化TagForm后,访问errors属性得到空字典。
问题原因
问题由三处代码错误共同导致:
- 表单基类使用错误:
TagForm继承自forms.Form,但内部编写了绑定模型的Meta配置类。Meta关联模型、自动生成字段的语法是forms.ModelForm的专属能力,普通Form类不会读取Meta内的配置,最终生成的表单没有任何绑定字段,传入的所有数据都会被直接忽略,字段校验、自定义clean方法完全不会执行。 - 字段配置值书写错误:ModelForm中引入模型全部字段的合法配置为
fields = '__all__'(双下划线包裹all关键字),代码中书写的'--all--'为无效值,即便基类修改正确,也会直接抛出表单配置异常。 - 校验流程未主动触发:Django表单不会在实例化阶段自动执行校验,必须手动调用
is_valid()方法后,才会依次执行字段默认规则校验、自定义clean方法,最终填充errors属性。实例化后直接访问errors时,校验流程尚未启动,返回值固定为空字典。
修复方案
对应三处错误逐一修改即可:
- 将
TagForm的基类从forms.Form改为forms.ModelForm - 将
Meta类中的fields = '--all--'修改为fields = '__all__' - 测试或业务逻辑中,访问
errors属性前必须先调用is_valid()方法触发校验流程
相关代码
原始模型代码
from django.db import models from django.urls import reverse class Tag(models.Model): name = models.CharField(max_length=50, db_index=True) slug = models.SlugField(unique=True, help_text='a label for url config') class Meta: ordering = ['name'] def __str__(self): return self.name.title() def get_absolute_url(self): return reverse('organizer:tag_detail', kwargs={'slug': self.slug})
原始错误表单代码
from django import forms from .models import Tag class TagForm(forms.Form): class Meta: model = Tag fields = '--all--' def clean_name(self): return self.cleaned_data['name'].lower() def clean_slug(self): new_slug = self.cleaned_data['slug'].lower() if new_slug == 'create': raise ValidationError('slug may not be "create".') else: return new_slug
修复后正确表单代码
from django import forms from .models import Tag class TagForm(forms.ModelForm): class Meta: model = Tag fields = '__all__' def clean_name(self): return self.cleaned_data['name'].lower() def clean_slug(self): new_slug = self.cleaned_data['slug'].lower() if new_slug == 'create': raise forms.ValidationError('slug may not be "create".') return new_slug
错误测试复现流程
In [11]: from organizer.forms import TagForm In [12]: tf = TagForm({'slug': 'create'}) In [13]: tf.errors Out[13]: {}
修复后正确测试流程
In [1]: from organizer.forms import TagForm In [2]: tf = TagForm({'slug': 'create'}) In [3]: tf.is_valid() # 必须先调用该方法触发校验 Out[3]: False In [4]: tf.errors Out[4]: {'name': ['这个字段是必填项。'], 'slug': ['slug may not be "create".']}
内容的提问来源于stack exchange,提问作者Mehdi Pourhabib
相关产品推荐
相关产品推荐

