Django框架(十四):Forms组件介绍及钩子函数

下面是小凰凰的简介,看下吧!
💗人生态度:珍惜时间,渴望学习,热爱音乐,把握命运,享受生活
💗学习技能:网络 -> 云计算运维 -> python全栈( 当前正在学习中)
💗您的点赞、收藏、关注是对博主创作的最大鼓励,在此谢过!
有相关技能问题可以写在下方评论区,我们一起学习,一起进步。
后期会不断更新python全栈学习笔记,秉着质量博文为原则,写好每一篇博文。

一、Forms组件用途

顾名思义,forms组件是不是和前端form标签有关系呢?对,可以这么想。

当我们在注册账号的时候是不是需要校验数据的格式、正确性等信息呢?就如下图。注册不符合规则是不是得有提醒,因此需要在页面中显示错误信息提示。

而其实这个底层过程是很复杂的,你想如果是你写的代码,你是不是得先对这些字段先取值,之后是不是得按不同规则一一校验。校验完后成功到无所谓,若错误是不是得一个一个构建错误信息渲染到模板的相应位置。这个过程是很复杂的。而form组件就是实现这个复杂的过程。

在这里插入图片描述

# forms组件的作用?
1. 校验数据'(本片博文重点讲这个)'
2. 页面显示错误信息
3. 渲染页面和重置数据

django的forms是可以做到根据数据库的字段,渲染前端这种类似登录注册的表单页面的,但实现出来很丑,当然它也支持我们自己调节样式,但是我认为前后端应该分离,后端的forms不应该插手前端的渲染,我前端登录注册页面自己写好,把数据发送给后端,后端采用forms进行数据校验即可,有错就返回字段以及对应的错误信息,根据字段找到对应的输入框,再在下面渲染错误信息即可!没错就执行数据库操作例如添加用户即可

二、Forms组件的使用语法

1、创建规则(创建一个forms类)

之前先看下models,对比一下forms和models!

# models.py
from django.db import models

class UserInfo(models.Model):
    user=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    email=models.CharField(max_length=32)

规则写在views.py文件里

from django import forms

class BookForm(forms.Form):
    user=forms.CharField(max_length=32)
    pwd=forms.CharField(max_length=32)
    email=forms.EmailField()
2、检验数据

我们在python console中输入检验

>>>from app01.views import BookForm
>>>fm=BookForm({"name":"lilz","pwd":123456,"email":"abc"})   # 要检验的数据====只校验规定的字段,规定的字段如果全对就是true,不检验其他字段,其他字段就是加进去也没有影响

>>>fm.is_valid()  # 查看是否合法,合法返回True(必须先查看是否合法)
False

>>>fm.cleaned_data  # 查看合法的字段
{'name': 'lilz', 'pwd': '123456'} =======字典
>>>fm.errors         # 查看不合法的字段
{'email': ['Enter a valid email address.', ]}

大家主要关注数据类型,方便后面取数据!
值得注意的是fm.errors并不是完全的字典套列表,只是说你可以这样想去取值。

3、实战演练
from django import forms
from app01.models import UserInfo # 引入模型
# 注意:这里的字段必须和前端页面input标签的name属性以及数据库中的字段保持一致
# 当然如果你不用form表单提交,采用ajax的json方式提交,你需要让字典的键和它们保持一致
class UserForm(forms.Form):  #创建校验规则类。,必须继承forms组件类
    name=forms.CharField(min_length=4,error_messages={"required":"该字段不能为空"}) #error_messages表示提示错误消息  #required代表为空的错误
    pwd=forms.CharField(min_length=6,max_length=18)
    email=forms.EmailField(error_messages={"invalid":"邮箱格式错误"})  #invalid代表格式的错误

def reg(request):
    if request.method=='POST':
        # 数据校验,我们把数据校验代码不放在这里,解耦 ===UserForm校验规则类
        form=UserForm(request.POST)    # 把数据放在规则类里校验
        if form.is_valid(): # 校验数据如果有效,则创建用户
            UserInfo.objects.create(**form.cleaned_data) # 符合规则后我们把数据插入到数据库中,因为数据是字典,所以需要打散
        else: # 否则如果无效,则把错误数据渲染到前端
            # print(form.cleaned_data) #{'pwd': 123, 'email': '250197@qq.com'}
            # print(type(form.cleaned_data))  # <class 'dict'>
            # print(form.errors) #<ul class="errorlist"><li>name<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
            # print(type(form.errors))  #<class 'django.forms.utils.ErrorDict'>   #{"name":["",]}
            # print(type(form.errors.get("name")))  #<class 'django.forms.utils.ErrorList'>   #["",]
            # print(form.errors.get("name")[0])  #name对应的错误信息
            error=form.errors
            return render(request,'reg.html',locals())  #把错误数据渲染到模板
    else:
        return render(request,'reg.html')

三、钩子函数—自定义规则

1、局部钩子

实现目标:实现注册功能,用户名不能重复、密码不能是纯数字

(1)数据库表模型
class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    email=models.CharField(max_length=32)
(2)匹配规则

局部钩子函数的函数名就是clean_字段名,你要给那个字段自定义规则,这个字段名就是谁!

from django import forms
from app01.models import UserInfo
from django.core.exceptions import ValidationError  #错误管理

class UserForm(forms.Form):  # 创建校验规则类。,必须继承forms组件类
    name=forms.CharField(min_length=5)
    pwd=forms.CharField()
    email=forms.EmailField()

    # 自定义钩子(匹配规则)
    # 用户名不能重复
    def clean_name(self):
        val=self.cleaned_data.get('name')  # 先取值
        ret=UserInfo.objects.filter(name=val)  # 查看数据库中是否有这个值
        if not ret: # 如果在数据库中没有,就通过匹配
            return val
        else:# 否则,说明在数据库中有该用户名
            raise ValidationError("用户名已存在")
            
    # 密码不能是纯数字
    def clean_pwd(self):
        val = self.cleaned_data.get('pwd')  # 先取值
        print(type(val))
        if val.isdigit():  # 判断是否是数字
            raise ValidationError("密码不能是纯数字")
        else:
            return val

局部钩子函数的格式一定要严格仿照上面的钩子函数写!什么时候返回错误,什么时候返回值!

(3)视图函数
def reg(request):
    if request.method=='POST':
        form=UserForm(request.POST)    #把数据放在规则类里校验
        if form.is_valid():#校验数据
            UserInfo.objects.create(**form.cleaned_data) #符合规则后我们把数据插入到数据库中,因为数据是字典,所以需要打散
        else:
            error=form.errors
            return render(request,'reg.html',locals())  #把错误数据渲染到模板
	else:
    	pass
2、全局钩子

实现目标:需要 确认密码 和 密码 进行比对。

上面的局部钩子,在钩子函数中我们只能拿到一个字段的值,为什么呢?我们就要看下源码了。如下:

(1)钩子函数源码剖析

在这里插入图片描述补充一下:add_error方法就是实现在cleaned_data删除字段及添加到error中

上面就是字段的max_length哪些验证加局部钩子自定义规则验证的核心代码了!相信我解释的很清楚了!对每个字段逐一循环验证,那么我们在对password进行自定义规则验证时,我们能在cleaned_data里拿到re_password的值吗?显然是不行的!在自定义阶段,能在cleaned_data里拿到值,前提是你必须通过了自带规则的验证!re_password要在passoword校验完之后才校验因此局部钩子无法完成需要两个字段参与的验证!

当我们把clean_fields函数执行完了,是不是cleaned_data就有了所有干净的符合要求的字段了!因此这时我们就可以定义全局钩子,来进行需要多字段参与的验证!

在这里插入图片描述
根据上图我们可以看出来clean_fields函数之后执行的是clean_form函数,我们来看下它的源码

在这里插入图片描述给大家看下源码的clean函数:
在这里插入图片描述

(2)数据库表模型
class UserInfo(models.Model):
    name=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    r_pwd=models.CharField(max_length=32)
    email=models.CharField(max_length=32)

注意表模型和forms规则很像,注意其区别,之所以像,也是因为,数据库字段名、forms字段规则名、form表单name属性或ajax传输字典的key都要一样造成的

(3)匹配规则
from django import forms
from app01.models import UserInfo
from django.core.exceptions import ValidationError  #错误管理


class UserForm(forms.Form):
    name=forms.CharField(min_length=5)  
    pwd=forms.CharField()
    r_pwd=forms.CharField()
    email=forms.EmailField()

    def clean(self):# 全局钩子
        pwd=self.cleaned_data.get("pwd")  
        r_pwd=self.cleaned_data.get("r_pwd")
        # 上面两个,有可能自带规则或自定义规则未通过,则get取值是空
        print("=======>")
        if pwd and r_pwd: # 如果两个都通过了第一层说明clean_data中有值就是true
            if pwd==r_pwd:
                print(1111)
                return self.cleaned_data
            else:
                print(222222)
                raise ValidationError("两次密码不一致")
        else:  
        '''
        如果两个只要有其中一个不在clean_data里,那就没必要在比较了,
        因为本身就已经在errors里了
        '''
            return self.cleaned_data
(4)视图函数
def reg(request):
    if request.method=='POST':
        form=UserForm(request.POST)   
        if form.is_valid():#校验数据
            UserInfo.objects.create(**form.cleaned_data) 
        else:
            error=form.errors # 拿到自定义规则或自带规则的错误信息
            
			'''
			第二层全局错误,__all__:全局错误信息
			如果全局错误里不为空,则取错误
			'''
            if form.errors.get("__all__"):
            	# 取全局钩子函数的匹配报错信息的方法
                g_error=form.errors.get("__all__")[0]
            return render(request,'reg.html',locals())  # 把错误数据渲染到模板
	else:
		pass
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凤求凰的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值