Django

您所在的位置:网站首页 js中label标签 Django

Django

2023-02-23 23:36| 来源: 网络整理| 查看: 265

Django-11:Forms组件 Forms组件一、引子1.1 forms组件 二、forms组件使用2.1 渲染标签的几种方式2.1.1 as_p2.1.2 .属性2.2.3 for循环 2.2 展示提示信息2.2.1 取消浏览器校验2.2.2 提示信息自定义 三、钩子函数(HOOK)3.1 案例1-用户名校验3.2 案例2-确认密码 四、forms渲染标签属性五、正则校验六、其他类型渲染

Forms组件 一、引子

需求:

书写一个具有注册功能的WEB页面,利用form表单提交数据,并在后端判断用户名和密码是否符合条件,如果不符合条件,需要将提示信息展示到前端页面上。

1.用户名汇总不能含有“孤儿”。

2.密码不能少于4位。

一、思路

前端页面上可利用行内标签的特性,用来占位。定义一个字典,该字典的key为uname_error和passwd_error,默认value为空。后端接收前端提交的数据,并进行判断,如不符合需求,则给key添加value通过rander(,locals())以及模板语法,给span标签添加内容。

代码执行流程:

​ 1、当第一次访问时,由于span标签没有内容,所以不在前端页面做展示。

​ 2、第一次提交数据时,后端定义字典的key可能会有值。

​ 3、如果数据不符合要求,则字典对应key的value则变成报错信息。

​ 4、由于form表单提交之后,页面刷新,会再次发送GET请求。

​ 5、而此时span标签就可以展示对应的报错信息。

二、代码

视图层

def ab_forms(request): # 该字典默认为空,对应的,初次访问页面的时候,是没有报错提示信息的。 back_dic = {'username':' ','password':' '} if requesthod == 'POST': username = request.POST.get('username') password = request.POST.get('password') if '孤儿' in username: back_dic['username'] = '违规用户名' if len(password) 注册 用户名: {{ back_dic.username }} 密码: {{ back_dic.password }}

三、效果展示

image-20211221224001651

​ 根据现象进行总结:

​ 1、再次刷新页面,提示信息仍然存在,因为dict中的value还是存在的,所以span标签仍然有数据

​ 2、提交之后,由于页面刷新,所以之前输入的数据也都没有了,体验不是很好。

1.1 forms组件

上述案例,我们自己做的事情:

手动书写前端获取用户数据的html代码(渲染html代码)后端对用户数据进行校验(校验数据)对不符合要求的数据进行前端提示(展示提示信息)

forms组件可以帮我们做到的事情:

渲染html代码校验数据展示提示信息

附:

为什么数据校验非要去后端,不能在前端利用js直接完成呢?

前端的校验是弱不禁风的,可以直接修改,或者利用爬虫程序绕过前端页面直接朝后端提交数据。购物网站场景下,选取了货物之后,会计算一个价格发送给后端,如果后端不做价格的校验,那么会造成很大损失。 二、forms组件使用

步骤:

视图层定义类,属性类似于模板层的字段。表单提交的数据,会和对应的“字段”规则进行校验,通过与不通过的“字段”值都会封装到对应方法中。有了错误提示信息之后,再次使用组件所提供的方法,来渲染标签。

一、视图层校验代码示例

''' 视图层 ''' from django import forms class TestForm(forms.Form): username = forms.CharField(min_length=3,max_length=8) # username字符串类型最小3位最大8位 password = forms.CharField(min_length=3,max_length=8) # password字符串类型最小3位最大8位 email = forms.EmailField() # email字段必须符合邮箱格式 [email protected]

二、如何校验

本小结主要介绍上面定义的TestForm类,如何发挥它的校验作用,由于是直接使用,所以并不是通过前后端交互的方式来展示效果,而是通过测试文件。

测试文件除了django内部的test.py文件以外,Pycharm内部也提供的有测试环境,点击右下角的,本小节的代码,都在这里进行测试。

基本方法:

1、将待校验的数据传入

In[2]: from app01.views import * In[3]: forms_obj = TestForm({'username':'ly','password':'123','email':'123@'})

2、判断数据是否合法

In[4]: forms_obj.is_valid() Out[4]: False ''' 该方法只有在所有的数据全部合法的情况下才会返回True '''

3、查看所有校验通过的数据

In[5]: forms_obj.cleaned_data Out[5]: {'password': '123'} ''' 实例化的时候,只有密码符合了TestForm类中的对应规则 '''

4、查看所有不符合校验规则,以及不符合的原因

In[6]:forms_obj.errors Out[6]: {'username': ['Ensure this value has at least 3 characters (it has 2).'], 'email': ['Enter a valid email address.']} # 字典key的value,之所以是列表的形式,是因为报错的信息,可能不止一条,比如不满足长度的同时,还包含了特殊字符或敏感词。

注意:

校验数据的时候,默认情况下数据可以多传但是绝不可能少传。

校验原理:

待校验数据的key,与类中的字段名进行匹配,如果相同,则将对应的value与类中的字段规则做校验,如果合法就放到cleaned_data,如果不合法则放到errors。在多传值的情况下,不管是cleaded_data还是errors,都不会放进去。当类中字段没有设置可为空时,少传则会放到errors里面。

本小结介绍了,如何使用组件来校验组件是否符合要求,如何展示在前端(渲染)详情见2.1章节

复杂的校验规则(如正则)等,在后续章节中,会陆续介绍。

2.1 渲染标签的几种方式

本章节将分为三个小章节来介绍三种不同的渲染方式。

三种方式各有各的好,觉得封装程度太高,留给自己二次开发的空间太小,那么就采用其他方式。 2.1.1 as_p

第一种:

forms组件实例化的对象中,有一个方法名叫as_p,在模板语法中使用可以渲染出表单。

但是,没有提交按钮

''' 视图层 ''' from django import forms class TestForm(forms.Form): username = forms.CharField(min_length=3, max_length=8) password = forms.CharField(min_length=3, max_length=8) email = forms.EmailField() def my_forms(request): # 1.先产生一个空对象 forms_obj = TestForm() # 2.直接将该空对象传递给html页面 return render(request,'test_forms.html',locals()) 注册 {{ forms_obj.as_p }}

效果如下图:

image-20211222180003072

现象:

可以看到,as_p 最终是渲染出了P标签,然后里面包裹着label标签和input标签 ''' 除了as_p以外,还有as_ul as_table 等 ''' as_ul : li标签 as_table : input框都在一行,类似于表头。 2.1.2 .属性

第二种:

组件类实例化的对象,可以通过 .属性的方式,来渲染出input标签 注册 {{ forms_obj.username }}

效果展示:

image-20211223112230874

现象:

虽然可以渲染出标签,但是输入框的前面,没有数据了,用户看到了不知道这里应该填写什么。

解决办法:

''' forms_obj.username可以拿到Input表单,而这个表单中又有一个名为label的属性,这个属性的值就是as_p中展示出来的值,默认格式为TestForm类中的属性名首字母大写。 ''' {{ forms_obj.username.label }} {{ forms_obj.username }} # 提示信息 输入框

此时就会遇到一个问题,如果不想要Username,觉得在页面上不好看,想换成中文的“用户名”,该如何操作呢?

''' 如何修改? 自己设置label属性的值,不要默认的。 ''' # views.py class MyForm(forms.Form): username = forms.CharField(min_length=3,max_length=8,label='用户名')

效果如下图:

image-20211223115509966 2.2.3 for循环

先来看看forms_obj循环出来的是什么?

{% for foo in forms_obj %} {{ foo }} {% endfor %} image-20211223115659737

现象:

可以看到foo在每次循环中,就等同于forms_obj.username、forms_obj.password、forms_obj.email。

那么我们想要获取到输入框前面的文本提示数据时,只需要foo.label即可。

因为: forms_obj.xxx = foo = input框 forms_obj.xxx.label = 提示信息

所以: foo.label = forms_obj.xxx.label = 提示信息

验证效果:

{% for foo in forms_obj %} {{ foo.label }}:{{ foo }} {% endfor %} image-20211223135633264 2.2 展示提示信息

在前面,介绍了如何定义“校验类”(TestForm)、一些常用的方法is_valid()、cleaned_data、errors,以及as_p等其他方式来渲染标签。

那么就差最后一步了,如何将提示信息展示在页面上,例:不符合邮箱格式、用户名不符合长度等。

本章节代码依旧和2、2.1章节一致.

from django import forms class TestForm(forms.Form): username = forms.CharField(min_length=3, max_length=8) password = forms.CharField(min_length=3, max_length=8) email = forms.EmailField() def forms_test(request): forms_obj = TestForm() return render(request,'forms_test.html',locals())

模板文件,由于组件并不会渲染出提交按钮,和form表单,所以需要进行补充:

注册 {% for foo in forms_obj %} {{ foo.label }}:{{ foo }} {% endfor %} 提交

渲染错误信息:

''' 2.0章节,我们知道了数据校验的格式为:TestForm({字典格式}) TestForm为自定义字段校验的类名 所以我们进行校验时代码是这样的 ↓↓↓ ''' forms_obj = TestForm() if requesthod == 'POST': username = request.POST.get('username') password = request.POST.get('password') email = request.POST.get('email') forms_obj = MyForm({'username':username,'password':password,'email':email}) ''' 是三个表单还好,可如果表单比较多,例如:调查问卷、在线考试测评这种。 那就会很麻烦。 ''' 仔细考虑下: 1.request.POST.get() 这个get我们还在那里见过?dict.get()? 对,就是字典,所以我们就可以将request.POST 看做成字典 2.MyForm({}) 这里刚好需要的就是字典,那么不就可以 MyForm(request.POST) 3.如果将request.POST 当做字典进行数据校验时,校验类中的字段名,必须和前端HTML标签中表单的name属性相同。

解决办法:

request.POST.get()这个get还在那里见过?dict.get()就是字典,所以我们可以把request.POST这个querydict对象看成是字典对象,随后作为参数,用于实例化form_obj对象。

最终代码为:

def forms_test(request): # 首先 生成空对象 forms_obj = MyForm() if requesthod == 'POST': # 校验数据 forms_obj = TestForm(requests.POST) # 校验结果如何合法,则操作数据库 if forms_obj.is_valid(): # 输入的数据合法,保存数据库,代码略,此处为了实验方便,只是返回字符串。 return HttpResponse('OK,注册成功') return render(request,'ab_forms.html',locals()) ''' foo为每个表单的输入框 .errors可以获取到所有错误信息的列表 如果不取索引为0的数据,那么在列表上渲染出来的格式就为ur>li,而非span标签 所以,为了不让它自动转换,这里可以errors.0,取索引第一位。 ''' #novalidate取消浏览器自动校验 {% for foo in forms_obj %} {{ foo.label }}:{{ foo }} {{ foo.errors.0 }} {% endfor %}

展示效果:

image-20211223162019721 2.2.1 取消浏览器校验

浏览器会根据我们的HTML标签,对表单进行简单的校验,例如当“用户名”输入框的长度太短,那么浏览器将无法提交,这样我们的错误信息就看不到效果,所以需要需要浏览器自动校验。

具体操作:

表单后跟上novalidate属性。 2.2.2 提示信息自定义

在2.2章节中,实现了错误信息提示,但是却是英文的,给用户的体验不好,所以我们需要自定义提示信息。

自定义提示信息:

对于继承forms.Form类(如案例中的TestForm)的属性,添加error_messages属性,示例如下:

class TestForm(forms.Form): username = forms.CharField(min_length=3,max_length=8,label='用户名',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(label='邮箱',error_messages={ 'invalid':'邮箱格式不正确', 'required':'邮箱不可为空', })

required:为空时自定义报错,如“用户名不能为空”。

min_length:最短长度,反义为max_length。

invalid:针对于邮箱格式问题,如:“邮箱格式不正确”。

默认为必填,选填以及身份证校验、手机号校验等,需要利用正则校验的,会在后续章节介绍。

三、钩子函数(HOOK)

在二章节中,可以发现只是简单的校验,并没有针对表单数据去做详细的校验,这个时候就需要利用钩子函数来进行处理

在forms组件中有两类钩子:

局部钩子:对单个字段的数据进行校验(如:用户名内是否含有敏感词。)全局钩子:对多个字段的数据进行校验(如:密码的二次确认。)

局部钩子:

格式: clean_字段

from django import forms class TestForm(forms.Form): username = forms.CharField(....略....) ''' 其他字段略 ''' def clean_username(self): username = self.cleaned_data.get('username') if '嘿嘿嘿' in username: # 展示错误信息,格式:add_error(字段,错误信息) self.add_error('username','携带敏感、低俗词汇') return username

钩子函数书写在类的内部,如果是局部钩子那么格式就为clean_字段,例如clean_username。

钩子函数的原理就是,通过forms.CharField校验之后,form_obj对象自动执行钩子函数,随后可以获取数据,并对其进行各种校验,如正则等。

随后通过add_error函数,给对应的字段添加错误信息,如self.add_error(‘username’,‘携带敏感、低俗词汇’)

最后一步,将**“钩”过来的数据“返回”**。

最后一步的return是必须的,因为分析源码内是有变量接收的,所以必须要return。

全局钩子:

格式:clean

from django import forms class TestForm(forms.Form): password = forms.CharField(....略....) confirm_password = forms.CharField(....略....) def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if password != confirm_password: self.add_error('confirm_password','二次密码不一致') return self.cleaned_data

全局钩子直接clean即可,但是钩子函数结束时,由于拿的是多个字段的数据,所以这里直接return self.cleaned_data即可。

3.1 案例1-用户名校验

案例:用户名中不可以出现’嘿嘿嘿’

from django import forms class MyForm(forms.Form): username = forms.CharField(min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名最多8位', 'required': '用户名不能为空', }) def clean_username(self): # 获取到用户名 username_dict = self.cleaned_data.get('username') if '嘿嘿嘿' in username: # 展示错误信息,add_error(字段,错误信息) self.add_error('username','携带敏感、低俗词汇') # 将钩子函数钩去出来数据再放回去 return username

由于是做用户名校验,针对单个字段,所以选用局部钩子,函数名为clean_username。

然后cleaned_data获取对应字段的数据,格式为字典,然后有通过内置方法get(),取值。

随后通过add_error(field,error)对指定的字段,添加错误信息。

最后,将“钩”出来的数据,再“放”回去,所以要记得return。

附:

在获取数据时,为什么使用的是cleaned_data而不是errors呢,因为钩子函数是在第一道校验完成之后才会进入后续校验的,所以肯定是符合前面的校验,自然数据就都在cleaned_data里。

3.2 案例2-确认密码

案例:注册页面密码的二次确认

表单中有两个密码输入框,第二个作为二次确认,当两个内的数据完全一致时才可以提交。

from django import forms class TestForm(forms.Form): ''' 基本的中文自定义报错,与基础校验代码略。 ''' username = forms.CharField(.....略) password = forms.CharField(.....略) confirm_password = forms.CharField(.....略) email = forms.EmailField(.....略) def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if password != confirm_password: # 添加错误信息 self.add_error('confirm_password','两次输入的密码不一致') # 全局钩子需要返回所有字段的数据。 return self.cleaned_data

由于是密码字段和确认密码这两个字段做校验,所以采用全局钩子,函数名直接为clean

四、forms渲染标签属性

在上文中,提到的有label属性、error_messages属性,那么本小结将介绍其他属性,如:表单默认值、input表单的类型是text还是passwd、等等等…

label、error_messages

作用:渲染表单时,修改提示性信息,不使用默认的字段名首字母大写。 后者则用于自定义报错信息。

from django import forms class TestForm(forms.Form): username = forms.CharField( # input框的提示信息(字段名) label = '用户名', # 自定义报错信息 eorros_messahes = { 'min_length': '用户名最少3位', 'max_length': '用户名最多8位', 'required': '用户名不能为空', }, )

initial、required

作用:initial设置默认值, required用于设置是否为空,False为允许为空。

from django import forms class TestForm(forms.Form): username = forms.CharField( initial = '张三', # 默认值,默认为“张三” required = False, # False允许为空,默认为True表示不允许为空 )

widget

作用:修改input表单的type属性的值,默认是text,当我们需要修改为file、password时,就需要利用widget去进行修改。

​ 另外,当我们的表单想要添加样式的时候,也需要使用到widget

''' 修改type属性值 ''' from django import forms class TestForm(forms.Form): username = forms.CharField(min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名最多8位', 'required': '用户名不能为空', }, widget=forms.widgets.TextInput(),) password = forms.CharField(min_length=3, max_length=8, label='密码', error_messages={ 'min_length': '密码最小3位', 'max_length': '密码最大8位', 'required': '密码不能为空', }, widget=forms.widgets.PasswordInput(),)

修改之后,这样password所属的表单,在输入时就不是明文的了。

当我们需要继承比如BootStrap样式的时候,就需要使用attrs方法。

具体格式为:forms.CharField( widget = forms.widgets.类型Input(attrs{‘class’:‘类1 类2 类3’}) ),多个类直接空格隔开。

''' 修改样式 ''' class TestForm(forms.Form): username = forms.CharField(min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名最多8位', 'required': '用户名不能为空', }, #指定样式 widget=forms.widgets.TextInput(attrs={'class':'form-control'}),) password = forms.CharField(min_length=3, max_length=8, label='密码', error_messages={ 'min_length': '密码最小3位', 'max_length': '密码最大8位', 'required': '密码不能为空', }, #指定样式 widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}),) 五、正则校验

上文中,我们实现了对数据长度进行简单校验,以及利用钩子函数对各个表单的内容进行更加详细的判断,正则校验可以在钩子函数内导入re模块,进行判断,但是本章节将要介绍的是,如何不使用钩子函数,直接就可以完成正则校验。

格式:

validators=[ RegexValidator(‘正则表达式’,‘错误提示’) ,RegexValidator(),RegexValidator()… ]

一个字段,可以通过多个正则表达式的校验,如果不通过,则显示指定的报错信息。

需求:校验手机号,并且还要是130开头的

''' 需求:校验手机号,并且还要是130开头的 ''' from django import forms # 导入模块 from django.core.validators import RegexValidator class MyForm(forms.Form): username = forms.CharField(min_length=3,max_length=8,label='用户名',) phone = forms.CharField( validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^130[0-9]+$', '必须是130开头的11位号码') ] )

image-20221115024721216

正则表达式尽量不要自己书写,可以在一些正则在线测试网站上,使用自动生成好的规则即可。

六、其他类型渲染

前面几个章节的代码中,永远都是forms.CharField(),如:

class MyForm(forms.Form): username = forms.CharField(min_length=3,max_length=8,label='用户名',) password = forms.CharField(widget=forms.widgets.PasswordInput(),)

所以本章节就是来介绍下其他标签,如radio、select等。

# 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() )


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3