一:引言
1:为什么了解forms组件?
顾名思义,forms组件是不是和前端form标签有关系呢?对,可以这么想。
当我们在注册网页的时候是不是需要校验数据呢?就如下图。当然注册不符合规则是不是得有提醒,因此需要在页面中显示错误信息提示。
而其实这个底层过程是很复杂的,你想如果是你写的代码,你是不是得先对这些字段先取值,之后是不是得按不同规则一一校验。校验完后成功到无所谓,若错误是不是得一个一个构建错误信息渲染到模板的相应位置。这个过程是很复杂的。而form组件就是实现这个复杂的过程。

2:forms组件的作用?
(1)校验数据
(2)页面显示错误信息
(3)渲染页面和重置数据
(4)解耦
二:Forms组件的使用语法
1:创建规则(创建一个forms类)
一般写在views.py文件里
from django import forms #注意:这里的字段必须和前端页面input标签的name属性以及数据库中的字段保持一致 class UserForm(forms.Form): #创建校验规则类。,必须继承forms组件类 name=forms.CharField(min_length=5) pwd=forms.IntegerField() email=forms.EmailField()
内置字段:博文
2:检验数据
我们在python console中输入检验
>>>from app01.views import BookForm >>>fm=BookForm({"name":"lilz","pwd":123,"email":"abc"}) #要检验的数据====只校验规定的字段,规定的字段如果全对就是true,不检验其他字段,其他字段就是加进去也没有影响 >>>fm.is_valid() #查看是否合法,合法返回True(必须先查看是否合法) False >>>fm.cleaned_data #查看合法的字段 {'name': 'lilz', 'pwd': '123'} =======字典 >>>fm.errors #查看不合法的字段 {'email': ['Enter a valid email address.', 'Enter a valid email address.']}
三:forms组件应用的案例--注册
1:目标-实现校验与页面显示信息的功能
用户名长度不能低于5位
密码必须是纯数字
邮箱必须符合邮箱格式
如果输入格式有错误,请显示在页面上
2:准备
(1)数据库相关
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)
====>数据库迁移
python manage.py makemigrations #同步 python manage.py migrate
3:上代码
(1)前端页面
template/reg.html
<style> .error{ color: red; margin-left: 10px; } </style> <body> <form action="" method="post"> {% csrf_token %} <p>用户名:<input type="text"name="user"><span class="error">{{ error.name.0 }}</span></p> <p>密码:<input type="password"name="pwd"><span class="error">{{ error.pwd.0 }}</span></p> <p>邮箱:<input type="email"name="email"><span class="error">{{ error.email.0 }}</span></p> <input type="submit"> </form> </body>
(2)后端代码
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('reg/', views.reg,name='reg'), ]
views.py
定义forms规则
from django import forms from app01.models import UserInfo #注意:这里的字段必须和前端页面input标签的name属性以及数据库中的字段保持一致 class UserForm(forms.Form): #创建校验规则类。,必须继承forms组件类 name=forms.CharField(min_length=5,error_messages={"required":"该字段不能为空"})#error_messages表示提示错误消息 #required代表为空的错误 pwd=forms.IntegerField() 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')
4:效果

5:分析整个流程
(1)访问http://127.0.0.1:8000/reg/ 并输入数据,这是一个get请求,
(2)数据经浏览器以http协议数据封装经网络到达服务器
(3)服务器在wsgi.py中以http协议解封装,经中间件的组件到达urls.py文件找到路径对应的视图函数,执行reg函数,reg函数中检查是get请求返回浏览器注册页面
(4)用户在注册页面输入数据点击提交,这是一个标签按钮,然后经过form标签中的路径访问服务器重复(2)(3)步骤到达reg函数,不过是post请求。
(5)post请求处理代码中调用form规则定义类匹配数据是否合规,若合规则把数据写入到数据库表中,不合则把错误不合规则的数据渲染到前端注册页面,然后把注册页面返回给浏览器
四:forms组件应用的案例--注册--优化
1:目标-实现校验、页面显示信息的、渲染页面和重置数据功能
本案例在上面案例的基础上实现
首先分析下上面的案例的缺陷,缺陷一:前端页面input还需要我们自己写,这比较麻烦;缺陷二:前端页面输入格式错误,虽然有提示错误,但我们输入的数据也已经没有了。我们的目标就是使用forms组件解决这缺陷。
2:需要知识点--实现渲染
方法一:简单但不灵活
前端页面reg.html
对于<label>/<input> 对,还有几个输出选项:
{{ form.as_table }}以表格的形式将它们渲染在<tr>标签中{{ form.as_p }}将它们渲染在<p>标签中{{ form.as_ul }}将它们渲染在<li>标签中
<body> <form action=""> {% csrf_token %} {{ form.as_p }} </form> </body>
后端view
def reg(request): if request.method=='POST': pass else: form=UserForm() #没有把我们输入的数据放进去查看是否匹配规则。我们的目的是把UserForm规则类的字段渲染到页面 return render(request,'reg.html',locals())
效果:


缺陷:
这种方法把样式写死了,虽然这种方法简单
方法二:(能实现保留数据,关键点在forms对象渲染)灵活但复杂
前端页面:
<style> .error{ color: red; margin-left: 10px; } </style> <body> <form action="" method="post"> {% csrf_token %} <p>用户名:{{ form.name }}<span class="error">{{ error.name.0 }}</span></p> <p>密码:{{ form.pwd }}<span class="error">{{ error.pwd.0 }}</span></p> <p>邮箱:{{ form.email }}<span class="error">{{ error.email.0 }}</span></p> <input type="submit"> </form> </body>
后端view
def reg(request): if request.method=='POST': # 数据校验,我们把数据校验代码不放在这里,解耦 ===UserForm校验规则类 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: form=UserForm() #没有把我们输入的数据放进去查看是否匹配规则。我们的目的是把UserForm规则类的字段渲染到页面 return render(request,'reg.html',locals())
现象
针对效果我们做下面分析
现象分析一:前端出现验证效果


正是因为我们定义的规则属性加入到了标签内,前端才能够在页面就可以控制匹配规则。这是浏览器的机制。每个浏览器都有不同的机制。这样是不靠谱的还是得用后端的匹配规则机制才行,当然前端有也是不错的。
那么该如何才能让前端不参与任何校验呢?
下面加入novalidate就能够达到此目的
<form action="" method="post" novalidate> {% csrf_token %} <p>用户名:{{ form.name }}<span class="error">{{ error.name.0 }}</span></p> <p>密码:{{ form.pwd }}<span class="error">{{ error.pwd.0 }}</span></p> <p>邮箱:{{ form.email }}<span class="error">{{ error.email.0 }}</span></p> <input type="submit"> </form>
现象分析二:前端的写过的数据依然保留--重置数据

为什么会这样呢?我们来分析下
(1)首先我们访问http://127.0.0.1:8000/reg/ get请求
(2)到达视图函数由于get请求,form=UserForm()是不带数据的,那么就会返回给浏览器渲染后的reg.html文件。
(3)当我们输入数据,点击提交按钮时,此时根据
<form action="" method="post">
依然会访问http://127.0.0.1:8000/reg/
不过此时是post请求。而这个时候form=UserForm(request.POST)是带着数据的
(4)因为 <p>用户名:{{ form.name }}<span class="error">{{ error.name.0 }}</span></p>
{{ form.name }}这个位置没有写死, 就会渲染出原来request.POST中的数据给浏览器
缺陷:
<p>用户名:{{ form.name }}<span class="error">{{ error.name.0 }}</span></p> 中的 {{ form.name }} 是渲染出来的,那么我们就无法对它更改样式了。也就是我们对这个input标签无法更改属性。
下面的方法就会解决这个问题====在定义的forms规则类中加属性
from django.forms import widgets #widgets魔法工具包 class UserForm(forms.Form): #创建校验规则类。,必须继承forms组件类 name=forms.CharField(min_length=5, error_messages={"required":"该字段不能为空"}, widget=widgets.TextInput(attrs={"class":"from-control"}) ) #TextInput表示input标签type=text
########################################################
#关于widget:
# 每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如<input type="text">。
# 在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">。
或者还有一种给属性添加类的方法:
from django import forms from django.forms import widgets class UserForm(forms.Form): user=forms.CharField(min_length=5,label="用户名") pwd=forms.CharField(min_length=5,widget=widgets.PasswordInput(),label="密码") #密码需要密文 r_pwd=forms.CharField(min_length=5,widget=widgets.PasswordInput(),label="确认密码") email=forms.EmailField(min_length=5,label="邮箱") # class Meta: #控制UserForm类的元类信息 def __init__(self, *args, **kwargs):#相当于修改forms类的__init__方法 super().__init__(*args, **kwargs) #走父类的这个方法 for filed in self.fields.values(): #循环每个字段对象 filed.widget.attrs.update({'class': 'form-control'}) #对每个属性添加一个类
方法三:
后端:
规则类
class UserForm(forms.Form): #创建校验规则类。,必须继承forms组件类 name=forms.CharField(min_length=5,label="用户名") pwd=forms.IntegerField(label="密码") email=forms.EmailField(label="邮箱")
views---没有变动
def reg(request): if request.method=='POST': # 数据校验,我们把数据校验代码不放在这里,解耦 ===UserForm校验规则类 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: form=UserForm() #没有把我们输入的数据放进去查看是否匹配规则。我们的目的是把UserForm规则类的字段渲染到页面 return render(request,'reg.html',locals())
前端页面
<style> .error{ color: red; margin-left: 10px; } </style> <body> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> <label for="">{{ field.label }}</label> {# 显示字段名:#} {{ field }}{# 显示input框:#} <span class="error">{{ field.errors }}</span> {# 显示错误信息:#} </div> {% endfor %} <input type="submit"> </form> </body>
效果:

参考:
浙公网安备 33010602011771号