Flask表单与表单验证实现流程介绍
作者:weixin_42576837 发布时间:2024-01-02 05:05:45
表单介绍
说到表单,在HTML中表单的创建时通过<form>
标签实现的,在<form>
标签内部,字段通过使用<input>
标签等定义。比如一个表单内部有用户名,密码框这些,都是通过<input>
,<label>
标签等实现的。
一个简单的表单:
<form>
First name:<br>
<input type="text" name="firstname">
<br>
Last name:<br>
<input type="text" name="lastname">
</form>
将表单提交给服务端处理时,服务端需要验证表单中的字段的取值是否符合要求。
在 Python 的 Web 开发中,表单内部的字段标签之类的,就不再使用HTML标签来写了,而是通过python类实现。
WTForms
在python中使用类定义表单,然后直接通过类定义生成对应的HTML代码,这种方式更加方便,而且使表单更易于重用。除非是非常简单的程序,或者想让表单的定义更加灵活,否则一般不会在模板中直接使用HTML代码写表单。
WTForms 和 Flask-WTF
WTForms 是一个灵活的表单验证和表单渲染的库,它的主要功能:
验证表单中的字段的取值是否符合要求;
渲染输出表单的 HTML 代码
WTForms 可以与任意的 Web 框架和模板引擎一起使用。 在 Flask 框架或者 Django 框架中,都可以使用 WTForms。
Flask-WTF
在 WTForms 的基础上提供了一些扩展,可以方便的在 Flask 框架中生成表单。
创建表单
下面直接用代码讲解如何创建表单。
首先,我们的目标是这样一个页面
一个简单的登录页面,让用户输入用户名,密码,同时对用户名和密码进行验证,验证成功就输出,验证不成功需要重新输入,并提示错误信息。
首先,这是一个表单,表单内有一些文本,有文本框,有登录按钮,这些都是通过python中的表单类创建的,使用的正是flask-wtf模块创建的。
先导入需要的模块
#导入表单类
from flask_wtf import FlaskForm
#导入字段类
from wtforms import StringField,SubmitField,PasswordField
#导入验证器类
from wtforms.validators import DataRequired,Length,Regexp
class LoginForm(FlaskForm):
'''
这些字段对象会被渲染为html标签
实例化一个文本字段对象,设置参数
label:这个值可以拿出来放在标签前面显示
validators=[]验证器列表,实例化的验证器对象,里面又可以设置参数
'''
#用户名字段
username = StringField(
label='用户名',
validators=[
DataRequired(message='用户名不能为空'),
Length(3,20,message='用户名长度在3-20个字符')
]
)
password = PasswordField(
label='密码',
validators=[
DataRequired(message='密码不能为空'),
Length(3,20,message='密码长度在3-20个字符'),
Regexp(r'^[a-z0-9A-Z]+$',message='密码只能有字母,数字,下划线组成')
]
)
submit = SubmitField(label='登录')
我们创建了一个类LoginForm
,它是一个表单类,继承了FlaskForm
,这个表单中包含一个用户名username字段,密码password字段,还有一个提交按钮submit,这三个字段作为了类LoginForm
的三个属性。
表单字段
我们发现用户名,密码这些实际是文本框,既然不用HTML代码实现,那么怎么实现呢?
使用的就是WTForms中的各种字段类,比如这里:
username = StringField()
StringField()
是WTForms 支持表单字段类,它表示文本字段,这样一个字段会被渲染为
<input id="username" name="username" type="text" value="">
注意:实例化对象的名称是username ,被渲染后的input标签中的id
和name
属性值都叫username
WTForms 支持如下类型的表单字段:
这只是一部分,还有很多其他支持的字段。
接着看代码:
username = StringField(
label='用户名',
validators=[
DataRequired(message='用户名不能为空'),
Length(3,20,message='用户名长度在3-20个字符')
]
)
验证器
StringField类需要传递一些参数:
label='用户名'
,这个参数可以直接在模板页面中显示,使用form.username.label
,把它放在文本框的前面,像下面这样:
validators=[ ]
这个参数表示对这个字段使用的验证器列表。验证器就是对这个字段使用那些验证,比如这里DataRequired,Length
两个验证器类,同样验证器类需要实例化然后传入参数。比如:
Length(3,20,message='用户名长度在3-20个字符')
限定长度在3-20字符,如果验证不通过,就弹出错误信息:message='用户名长度在6-20个字符'
。
验证器也有很多类型,常见的验证器类有:
还可以自定义验证器类等等。
我们创建了一个单独的文件loginform.py
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,Regexp,Length
class LoginForm(FlaskForm):
#<input id="username1" maxlength="20" minlength="3" name="username1" required type="text" value="">
username = StringField(
label='用户名',
validators=[
DataRequired(message='用户名不能为空'),
Length(3,20,message='用户名长度在3-20个字符')
]
)
password = PasswordField(
label='密码',
validators=[
DataRequired(message='密码不能为空'),
Length(3,20,message='密码长度在3-20个字符'),
Regexp(r'^[a-z0-9A-Z]+$',message='密码只能有字母,数字,下划线组成')
]
)
submit = SubmitField(label='登录')
表单类创建好之后,可以做一个简单的测试:
把这个表单显示出来
首先,我们在app.py文件中:
from flask import Flask,render_template,request
from loginform import LoginForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
@app.route('/',methods=['GET','POST'])
def login():
loginform = LoginForm()
if request.method == 'GET':
return render_template('login.html',form = loginform)
return 'hello'
if __name__ == '__main__':
app.run()
app.config['SECRET_KEY'] = 'hard to guess string'
用于防范 CSRF 攻击,具体的我也不清楚,就不再细说了,总之需要设置
接着,在根路由下/
,有视图函数login
,访问这个路由的方法可以是GET,或者POST。首先假设是GET,我们就需要把之前的表单渲染出来,具体的做法就是:
使用创建的表单类LoginForm
实例化一个表单对象loginform ,如果请求方法是GET,就去渲染login.html
,然后表单对象作为参数传递过去。所以我们还需要设计一下login.html
文件。
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="{{ url_for('login') }}" method="post">
<table>
<tbody>
<tr>
<td>{{ form.username.label }}</td>
<td>{{ form.username }}</td>
<td>{% for err in form.username.errors %}
{{ err }}
{% endfor %}
</td>
<td>{{ form.test }}</td>
</tr>
<tr>
<td>{{ form.password.label }}</td>
<td>{{ form.password }}</td>
<td>{% for err in form.password.errors %}
{{ err }}
{% endfor %}
</td>
</tr>
<tr>
<td>{{ form.submit }}</td>
</tr>
{{ form.hidden_tag() }}
</tbody>
</table>
</form>
</body>
</html>
这里使用了一个表格布局,然后表单的action="{{ url_for('login') }}" method="post"
,设置了表单的提交路径,以及提交方法。
<td>{{ form.username.label }}</td>#拿到username的label值显示出来
<td>{{ form.username }}</td>#显示username这个字段
<td>{% for err in form.username.errors %}#这是错误信息,如果验证不通过会显示错误信息
{{ err }}
{% endfor %}
</td>
最后,还要注意到: {{ form.hidden_tag() }}
, 用于防范 CSRF 攻击,生成 <input id=“csrf_token”/>
标签。总之必须要加上,不加上,后面验证数据的时候会出问题。
接着,运行app.py,访问根路径/
,则是GET方法访问,会渲染出login.htm
l文件。
接着,我们需要实现,用户输入数据,我们进行验证,验证不成功就提示错误信息,验证成功就登录成功。
回到表单类中,我们可以发现使用的验证器有这几种:
其中,DataRequired,Length直接被渲染为HTML中input标签的属性:
maxlength="" minlength="" required
这时候验证就是在浏览器上完成的了,而不是在服务器。客户端方式可以实时动态的提示用户输入是否正确,只有用户输入正确后才会将表单数据发送给服务器。客户端验证可以增强用户体验,降低服务器负载。
参考书上说,Flask程序中使用WTForms实现的就是服务器验证,但是有些字段又会被渲染为HTML5的属性,所以也不全是服务器验证。
这就是浏览器给出的验证提示
但是正则验证器,确实是在服务端完成验证的
Regexp(r'^[a-z0-9A-Z]+$',message='密码只能有字母,数字,下划线组成')
那么怎么在服务器验证数据呢,首先,我们的数据会提交到/
路径,使用的是POST方法。
表单类对象loginform,有一个验证方法,loginform.validate()
,调用这个方法时,会去调用你每一个字段中使用的每一个验证器去验证数据,全部验证通过返回True,失败返回False。
@app.route('/',methods=['GET','POST'])
def login():
loginform = LoginForm()
if request.method == 'GET':
return render_template('login.html',form = loginform)
elif request.method == 'POST' and loginform.validate():
return f'用户 {loginform.username.data}登录成功'
else:
return render_template('login.html',form = loginform)
如果请求方法时GET,直接渲染表单
如果请求方法时POST,并且
loginform.validate()==True
,表示验证通过,这时候我们返回登录成功,同时使用loginform.username.data
可以拿到用户输入的用户名。否则,验证失败,再次渲染这个表单,注意:这时候,调用了
validate()
方法,返回False,产生了错误信息,错误信息在form.username.errors
,是一个列表,这时候login.html中的错误信息列表就是有输出了。
测试一下:我的密码字段设置了正则验证,只允许输入字母数字下划线,而且字符个数在3-20个。
首先,不填写字段,浏览器端会自动验证
输入正确格式的密码:
输入错误格式的密码:
来源:https://blog.csdn.net/weixin_42576837/article/details/126404406


猜你喜欢
- 您可以使用 ObjectContext 对象提交或放弃一项由 Microsoft Transaction Server (MTS) 管理的事
- 记录一下安装win10+GeForce GTX1060+CUDA 9.0+cuDNN7.3+tensorflow-gpu 1.12.0+py
- 如何使用数据绑定控件实现不换页提交数据?Chunfeng.html' 提交页面< html><
- 1.什么是接口接口就是一种规范与标准,在生活中经常见接口,例如:笔记本电脑的USB接口,可以将任何厂商生产的鼠标与键盘,与电脑进行链接。为什
- 开发工具python版本:3.6.4相关模块:pygame;以及一些python自带的模块。环境搭建安装python并添加到环境变量,pip
- Python通过命令提示符安装matplotlib:1.直接打开命令提示符(快捷键窗口+ r)2.若提示安装失败(Python - 您正在使
- 本文实例讲述了JavaScript DOM节点操作方法。分享给大家供大家参考,具体如下:使用DOM可以新建HTML元素,也可以删除已有的HT
- 在网上搜索的时候,经常看到两种打开方式: dispatch和EnsureDispatchimport win32com.client as
- 最近从某网站下载了一批文档,但是文件是用数字串命名的文档(很多图书馆都这样吧),现在我也下载完了这些文件,也有这些文件的列表,就是不能一个一
- 问题:需要循环获取网元返回的某个参数,并计算出平均值。解决方案:通过expect解决返回More的问题。通过具体的参数位置,精确获取到参数。
- 目录一、定义二、作用三、导入1.import导入import 模块名from importfrom 模块名 import *总结一、定义包含
- 一、使用xls和xlsx处理Excel表格xls是excel2003及以前版本所生成的文件格式;xlsx是excel2007及以后版本所生成
- 一、简介我们来看看对 Vuex 比较专业的介绍:Vuex 是一个专为 Vue 开发的应用程序的状态管理模式,它采用集中式存储管理应用的所有组
- 本文主要介绍Python中,class(类)的装饰器@staticmethod和@classmethod的使用示例代码和它们的区别。1、@s
- 一、写在前面从学 Python 的第一天起,我就知道了使用 pip 命令来安装包,从学习爬虫到学习 Web 开发,安装的库越来越多,从 re
- 你知道(X)HTML中最多余的标签中是什么吗?在我看来就是这个<a>标签,不错,就是每个网站使用最多的超级链接标签<a&g
- 编写Python代码,大家都需要遵循PEP8,因此在pycharm中,如何设置每行最大长度限制,成为了一个小的知识盲点,在这里做一下记录,方
- 同一台服务器上部署多个项目时,项目可能使用不同版本的django或者其它不同的python库,这种情况下可以使用virtualenv来创建独
- 在本机运行含有JavaScript代码的网页时(比如Google AD代码),IE浏览器会产生一个警告。这个“警告”确实很烦人,开始时还会误
- session的超时时间设置settings中SESSION_COOKIE_AGE=60*30 30分钟。SESSION_EXPIRE_AT