Forms组件

forms组件前戏

题目:写一个注册功能,获取用户名和密码 利用form表单提交数据,在后端判断用户名和密码是否符合一定的条件:用户名中不能含有xxx,密码不能少于三位。如果不符合条件需要你将提示信息展示到前端页面

思路:在前端页面的input标签后面加上和两个span标签,标签里面放上后端传回的信息,后端代码里面分别对提交的用户名和密码信息进行验证,讲验证之后的信息添加到已经封装好的字典中。

{#前端代码#}
<form action="" method="post">
    <p>
        用户名:<input type="text" name="username">
        <span style="color: red">{{ back_dict.username }}</span>
    </p>
    <p>
        密码:<input type="password" name="password">
        <span style="color: red">{{ back_dict.password }}</span>
    </p>
    <p><input type="submit" value="提交"></p>
</form>
#后端代码
def index(request):
    back_dict = {'username':'','password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if 'xxx' in username:
            back_dict['username'] = '不符合社会主义核心价值观'
        if len(password)<3:
            back_dict['password'] = '密码不能小于三位数'

    return render(request,'index.html',locals())

在这次说明一下,在实际项目中是必须要在后端对用户输入的数据进行校验,因为前端代码可以直接修改,利用爬虫等程序可以轻松绕过前端的验证,后端对用户输入的数据必须进行一个校验。

利用上述代码代码进行校验太low了,如何利用forms组件进行校验呢?

forms组件能够完成的事情:1.渲染html代码 2.校验数据 3.展示提示信息

接下来讲一下

forms组件的基本使用:

写在views视图文件中:先导入forms模块,新建一个类,属性的字段参数中常见的有:label:字段名(对应前端页面中input标签前面的解释,用户名,密码等等),error_messages :自定义报错信息,required:控制字段是否为必填字段


from django import forms
class MyForm(forms.Form):
    #定义username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8,label='用户名',initial='David',
                               error_messages={
                                   'min_length':'用户名不能少于3个字符',
                                   'max_length':'用户名最大不能超过8个字符',
                                   'required':'用户名不能为空'
                               }
                               )
    password = forms.CharField(min_length=3,max_length=8,label='密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最大8位',
                                   'required': "密码不能为空"
                               },
                               )
    email = forms.EmailField(error_messages={
                                 'invalid':'邮箱格式不正确',
                                 'required': "邮箱不能为空",
                             },label='邮箱',required=True,
                            )

在python console中可以对定义的报错信息进行初始校验,方法如下:

from app01 import views
#1 实例化一个类对象,将带校验的数据组织成字典的形式传入
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
#2 判断数据是否合法,该方法只有在所有的数据全部合法的情况下才会返回True form_obj.is_valid() False
#3 在完成判断数据是否合法之后,可以查看所有校验通过的数据(注意:这个方法只有在判断数据是否合法之后才能有的方法,如果未进行第二步的校验,无没有该方法) form_obj.cleaned_data {'username': 'jason', 'password': '123'}
#4 查看所有不符合校验规则以及不符合的原因 form_obj.errors { 'email': ['Enter a valid email address.'] }
# 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略,例如: form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'}) form_obj.is_valid() True
# 6 校验数据 默认情况下 类里面所有的字段都必须传值(默认数据可以多传,不能少传)
form_obj = views.MyForm({'username':'jason','password':'123'}) form_obj.is_valid() 
False

在后端定义了需要验证的字段之后,不需要在前端页面中重新书写标签代码,可以直接在前端对标签进行渲染:

三种渲染方式

#后端代码 views.py

def ab_form(request):
    #1.先实例化一个组件类空对象
    form_obj = MyForm()
    #2 直接将该空对象传递给后端页面
    return render(request,'ab_form.html',locals())
{#前端代码 ab_form.html#}
<body> {#<p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>#} {# {{ form_obj.as_p }}#} {# {{ form_obj.as_ul }}#} {# {{ form_obj.as_table }}#} {#<p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多 一般情况下不用</p>#} {#<p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>#} {#<p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>#} {#<p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>#} <p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p> {% for form in form_obj %} <p>{{ form.label }}:{{ form }}</p> {% endfor %} </body>

渲染好了标签之后,如何将验证信息反馈在前端页面呢?首先,浏览器会自动帮你校验数据,但是前端的校验弱不禁风,但是你如果不做校验呢?可以给form表单加一个novalidate属性

<form action="" method="post" novalidate>

如果标签是渲染出来的如何进行展示校验信息呢?

#后端代码
def ab_form(request):
    #1.先实例化一个组件类空对象
    form_obj = MyForm()
    if request.method == 'POST':
        #首先获取用户数据并进行校验,从面前对报错信息进行验证分析可以知道,被校验数据需要构造成字典传入才行,request.POST获得的数据就可以看成是一个字典
        #3校验数据
        form_obj = MyForm(request.POST)
        #必须先判断数据是否合法
        if form_obj.is_valid():
            #5 如果合法,接下来进行数据库操作,存入数据
            return HttpResponse('OK')
            #5 不合法,有错误,这里什么也不需要写,直接走后面的代码,将form_obj传回去
        #2 直接将该空对象传递给后端页面
    return render(request,'ab_form.html',locals())
{% for form in form_obj %}
        <p>
            {{ form.label }}:{{ form }}
{#此时form_obj中已经包含前面传回来的错误信息了,可以直接用,参考前面说过的对错误信息校验#}
            <span style="color: red">{{ form.errors.0 }}</span>
        </p>
{% endfor %}

注意点:1.必备的条件 get请求和post传给html页面对象变量名必须一样,因为post请求过来进行校验之后如果有错误信息相当于将页面刷新,不一样的话之前,一开始get请求时候的代码就没办法用了

    2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改,更加人性化

在这里补充一点内容:如果没有指定错误信息的话,错误信息提示是英文的,可以通过指定错误信息来对需要展示的错误信息进行修改。修改后的错误信息就是放在上面的error_messages字段参数中,以字典的形式表示出来

 

钩子函数:在特定的节点自动触发完成响应操作,钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则

在forms组件中有两类钩子:
1.局部钩子
  当你需要给单个字段增加校验规则的时候可以使用
2.全局钩子
  当你需要给多个字段增加校验规则的时候可以使用

实际案例:1.校验用户名中不能含有xxx 只是校验某一个字段,使用局部钩子  2.校验密码和确认密码是否一致,需要对比password和confirm_password两个字段,需要用到全局钩子

需要用到钩子函数的时候,直接在类里面直接书写钩子函数即可

# 局部钩子
    def clean_username(self):
        # 获取到用户名
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误信息
            self.add_error('username','光喊666是不行滴~')
        # 将钩子函数钩去出来数据再放回去,获取到了什么,再把什么放回去
        return username
# 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password','两次密码不一致')
        # 将钩子函数钩出来数据再放回去
        return self.cleaned_data

forms组件其他字段参数及补充知识点

常见的参数有:

label 字段名
error_messages 自定义报错信息
initial 默认值,对应input框中的value属性
required 控制字段是否必填

如果字段没有样式,如何针对不同类型的input进行操作修改?text  password  date  radio  checkbox等标签属性

要给哪个标签添加属性就在相应的组件类下面的属性参数里面添加

eg: 

#在组件类下面password属性下面添加如下代码,表示给该标签加上一个password属性,后面表示增加一个class属性,其他的不同样式用空格隔开
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})

在对手机号码进行校验的时候经常用到正则校验

#先导入校验模块
from django.core.validators import RegexValidator
然后在定义好的forms组件类里面添加正则校验参数
phone = forms.CharField(
        validators=[
            RegexValidator(r'^[0-9]+$', '请输入数字'),
            RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
        ],

其他类型渲染:不需要死记硬背,需要用的时候过来看一下,直接拿过去用

    # radio
    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )
    # select
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )
    # 多选
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    # 单选checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
    # 多选checkbox
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )
posted @ 2020-10-25 17:49  方方的鱼  阅读(169)  评论(0)    收藏  举报