Django强大的form表单之 is_valid

本文详细解析了Django框架中的表单验证过程,包括is_valid()方法的工作原理,错误处理机制,以及如何利用clean_XX钩子自定义验证规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们看看一般验证过程:
1.方法函数is_valid()的作用检查seld.errors是否都正确,例如长度,空值,类型等
2.分析errors.里面判断_errors是都为空,如果为空返回self.full_clean(),否则返回self._errors
3.跳到full_clean(),该函数里面设置_errors和cleaned_data这两个字典,分别是存放存错误字段和正确字段的。
4.在full_clean的最后有是[self._clean_fields()],表示校验字段,(5,6,7是关于_errors和cleaned_data的左右)
5._clean_fields函数开始循环校验每个字段,而真正校验字段的是field.clean(value)
6.在_clean_fields中可以看到,会将字段按结果添加到_errors和cleaned_data这两个字典中
7.结尾部分还设置了钩子,找clean_XX形式的,并且会执行。执行错误信息也会添加到_errors中
至此校验完成~~

下面举个栗子
def login(request):
    if request.method == "POST":
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():#如果检验全部通过
            print(form_obj.clean_data) #这里全部都没问题,这部实际中不用只是看看结果所以打印出来
            #一般情况下接下来要严重该字段是否存在并且吻合(这里用用户名和密码匹配)
            name = forms.cleaned_data.get('name')
            password = forms.cleaned_data.get('password')
            #authenticate函数会自动帮你验证是否匹配,这也是Django强大之处
            user = authenticate(request,username=username,password=password)
            if user: #如果匹配成功
                return HttpResponse("登錄成功")
            else:
                return HttpResponse("用戶名或者密碼錯誤")
        else:  #严重失败的话,看看clean_data和errors中的内容
            print(form_obj.clean_data)
            print(form_obj.errors)
            return render('严重失败,错误原因如下',request, "login.html", {"form_obj": form_obj,)

    form_obj = LoginForm()
    return render(request, "login.html", {"form_obj": form_obj})

 举个钩子代码的例子

def clean_user(self):
    val1 = self.cleaned_data.get("user")
    #从正确的字段字典中取值
    #如果这个字符串全部都是由数组组成
    if not val1.isdigit():
        return val1
    else:
        # 注意这个报错信息已经确定了
        raise ValidationError("用户名不能全部是数字组成")
在校验的循环中except ValidationError as e:,捕捉的就是这个异常,所以能将错误信息添加到_errors中

以上就是form表单的一个小应用,下面分享一下对源代码的理解
参考了《django web开发指南》

def is_valid(self):
    """
    Returns True if the form has no errors. Otherwise, False. If errors are
    being ignored, returns False.
    如果表单没有错误,则返回true。否则为假。如果错误是被忽略,返回false。
    """
    return self.is_bound and not self.errors
    #is_bound默认有值
    #只要self.errors中有一个值,not True = false,返回的就是false


def errors(self):
    """
    Returns an ErrorDict for the data provided for the form
    t在form表单存在的前提下,返回一个ErrorDic(错误集)
    """
    if self._errors is None: #如果全部正确就转到==>self.full_clean()
        self.full_clean()
    return self._errors


def full_clean(self):
    """
    Cleans all of self.data and populates self._errors and self.cleaned_data.
    清除所有的self.data和本地的self._errors和selif.cleaned_data
    """
    self._errors = ErrorDict()
    if not self.is_bound:  # Stop further processing.停止进一步的处理
        return
    self.cleaned_data = {}

    """
    # If the form is permitted to be empty, and none of the form data has
    # changed from the initial data, short circuit any validation.
    #如果表单允许为空,和原始数据也是空的话,允许不进行任何验证
    """

    if self.empty_permitted and not self.has_changed():
        return

    self._clean_fields()   #字面意思校验字段
    self._clean_form()
    self._post_clean()



def _clean_fields(self):
    #每个form组件实例化的过程中都会创建一个fields。fields实质上是一个字典。
    #储存着类似{"user":"user规则","pwd":"pwd的规则对象"}
    for name, field in self.fields.items():
        #name是你调用的一个个规则字段,field是调用字段的规则
        #items是有顺序的,因为他要校验字段的一致性
        """
        # value_from_datadict() gets the data from the data dictionaries.
        # Each widget type knows how to retrieve its own data, because some
        # widgets split data over several HTML fields.
        
        value_from_datadict()从数据字典中获取数据。
        每个部件类型知道如何找回自己的数据,因为有些部件拆分数据在几个HTML字段。
        """
        #现在假设第一个字段是user
        if field.disabled:
            value = self.get_initial_for_field(field, name)
        else:
            value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
        try:
            if isinstance(field, FileField):  #判断是不是文件
                #你是文件的时候怎么校验
                initial = self.get_initial_for_field(field, name)
                value = field.clean(value, initial)
                #filed是一个对象,field.clean才是真正的规则校验
            else:
                #你不是文件的时候怎么校验
                #实际中也是走的这一部,value是你输入的字段值
                #如果没有问题,那么原样返回
                value = field.clean(value)
                #如果一旦出现问题,那么就会走except中的代码
            self.cleaned_data[name] = value

            if hasattr(self, 'clean_%s' % name):  #这里找是否有clean_XX这个名字存在
                value = getattr(self, 'clean_%s' % name)()  #如果有执行这个函数
                self.cleaned_data[name] = value  #而在钩子中必须报错的返回值是确定的
                #如果上面有问题,就又把错误添加到了_error中
                #上面这三行代码是我们能添加钩子的原因,而且规定了钩子名的格式

                #如果这个值是正确的话,就会给这个字典添加一个键值对
                #刚才在full_clean中self.cleaned_data = {}已经初始化了。
                #{”pws“:123}
        except ValidationError as e:
            self.add_error(name, e)
            #如果出现错误,就会给_error这个字典添加一个键值对
            #至于add_error这个函数如何添加这个键值对的,我们先不管
            #键就是name,值就是错误信息e
            #在full_clean中已经初始化self._errors = ErrorDict()
            #假设现在user有问题,那么_error就是这样{”user“:e}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值