目录
通过Flask处理表单
通过Flask-WTF处理表单
通过Flask-WTF验证表单
通过Flask处理表单
表单是在网页中搜集用户信息的各种表单控件的集合区域,表单控件包括文本框、单选框、复选框、提交按钮等,用于实现客户端和服务器端之间的数据交互。
利用Flask内置的功能对表单进行处理的过程:
首先在模板文件中通过HTML代码创建表单,然后通过请求上下文中的request.form对象获取以及验证表单数据,最后通过消息闪现给用户反馈正确或错误提示。
例如用户注册的案例:
(1)创建一个Flask项目,在项目中新建templates文件夹,在该文件夹下创建模板文件register.html,在该模板文件中使用<form>标签创建表单。
<h1>注册页面</h1>
{#给用户展示不同的消息闪现#}
{% macro print_error(type) %}
{% for message in get_flashed_messages(category_filter = (type)) %}
<p class="error" style="color: red;
display:inline;">{{ message }}</p>
{% endfor %}
{% endmacro %}
<form action="" method=post>
<span>用户名:</span><br>
<input type=text name=username>{{ print_error('message') }}
{{ print_error('info') }}<br>
<span>密码:</span><br>
<input type=password name=password><br>
<span>确认密码:</span><br>
<input type=password name=password2>{{ print_error('error') }}<br>
<p><input type=submit value=注册></p>
</form>
(2)在app.py文件中定义视图函数register(),该视图函数用于展示注册页面以及验证用户输入的注册数据是否符合要求。
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST': # 判断请求方式
username = request.form.get('username') # 获取表单数据
password = request.form.get('password')
password2 = request.form.get('password2')
if not all([username, password, password2]): # 验证数据的完整性
flash('请填入完整信息', category='message')
# 验证输入的数据是否符合要求
elif len(username) < 3 and len(username) > 0 or len(username) > 15:
flash('用户名长度大于3且小于15', category='info')
elif password != password2: # 验证两次输入的密码是否一致
flash('密码不一致', category='error')
else:
return '注册成功'
return render_template('register.html')
通过Flask-WTF处理表单
处理表单涉及创建表单、验证表单数据、获取和保存表单数据、反馈错误提示等诸多操作,为了降低处理表单的难度,Flask提供了专门负责处理表单的扩展包——Flask-WTF。
Flask-WTF的安装
pip install flask-wtf
Flask-WTF是构建于 WTFForms之上的,所以引用的时候:
from flask_wtf import FlaskForm
常用字段类与表单控件的映射关系:
字段类 | 表单控件 | 说明 |
BooleanField | <input type="checkbox"> | 复选框,值为True或False,默认值为Flase |
DataField | <input type="text"> | 文本字段,值为datetime.date对象 |
DataTimeField | <input type="text"> | 文本字段,值为datetime.datetime对象 |
DecimalField | <input type="text"> | 文本字段,值为decimal.Decimal |
FileField | <input type="file"> | 文件上传字段 |
FloatField | <input type="text"> | 浮点数字段,值为浮点型 |
IntegerField | <input type="text"> | 整数字段,值为整型 |
RadioField | <input type="radio"> | 一组单选按钮 |
SelectField | <select><option></option></select> | 下拉列表 |
SubmitField | <input type="submit"> | 提交按钮 |
StringField | <input type="text"> | 文本字段 |
PasswordField | <input type="password"> | 密码文本字段 |
TextAreaField | < textarea></textarea> | 多行文本字段 |
HiddenField | <input type="hidden"> | 隐藏文本字段 |
补充:datetime.date和datetime.datetime的区别
datetime.date类代表日期,它包含年、月和日的信息,但不包含具体的时间(小时、分钟和秒)信息。
datetime.date(year, month, day)构造函数创建一个日期对象,其中year、month和day分别表示年、月和日的整数值。
datetime.datetime类则代表日期和时间,它包含年、月、日以及具体的时间(小时、分钟和秒)信息。
datetime.datetime(year, month, day, hour=0, minute=0, second=0)构造函数创建一个日期时间对象,其中year、month、day、hour、minute和second分别表示年、月、日、小时、分钟和秒的整数值。
常用的字段类都继承自WTForms库的Field类,可以通过Field类的构造方法实例化所有字段类,以下是一些可配置的参数:
参数 | 说明 |
label | 字段标签<label>的值,即显示在输入控件旁的说明性文字 |
render_kw | 字典类型,用于设置控件的属性,包括提示信息(placeholder)、高度(height)、宽度(width )、是否获得焦点(autofocus )等。 |
validators | 列表类型,包含一系列的验证器,在提交表单数据时,会被列表中的验证器逐一验证 |
default | 字符串或可调用对象,为表单字段设置默认值 |
参数validators的值是一个列表,包含了一系列用于验证表单数据是否有效的验证器,只有当表单数据满足验证器的规则时,数据才能成功提交到服务器。
- 在使用验证器之前需要先从wtforms.validators模块中导入相应的类:
验证器 | 说明 |
DataRequired(message=None) | 验证数据是否有效,空字符串为无效数据 |
Email(message=None) | 验证数据是否为电子邮件地址 |
EqualTo(fieldname,message=None) | 验证两个字段值是否相同 |
IPAddress(ipv4=True, ipv6=False, message=None) | 验证数据是否为有效IP地址 |
Length(min=-1,max=-1,message=None) | 验证输入值的长度是否在给定的范围内 |
NumberRange(min=None,max=None,message=None) | 验证输入的数字是否在给定的范围内 |
Optional(strip_whitespace=True) | 允许字段中没有输入,将跳过其他验证函数 |
Regexp(regex,flags=0,message=None) | 使用正则表达式验证输入值 |
URL(require_tld=True,message=None) | 验证URL |
AnyOf(values, message=None,values_formatter=None) | 确保输入值在可选值列表中 |
NoneOf(values, message=None,values_formatter=None) | 确保输入值不在可选值列表中 |
用Flask-WTF创建表单:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
app = Flask(__name__)
class RegisterForm(FlaskForm):
username = StringField(label='用户名:',
validators=[DataRequired(message='用户名不能为空'),
Length(3, 15, message='长度应该为3~15')])
password = PasswordField('密码:',
validators=[DataRequired(message='密码不能为空')])
password2 = PasswordField('确认密码:',
validators=[DataRequired(message='密码不能为空'),
EqualTo('password', message='两次密码不一致')])
submit = SubmitField('注册')
使用Flask-WTF创建了注册表单,但此时在模板文件中还无法渲染创建的表单。
- 如果希望在模板文件中渲染通过Flask-WTF创建的表单:
① 需要在视图函数中将表单类的对象传递到模板文件中。
②在模板文件中获取表单字段,将表单字段渲染到HTML页面进行呈现。
#在项目的app.py文件中定义用于传递表单类对象的视图函数
from flask import render_template
#,默认情况下Flask-WTF为每个表单启用CSRF保护,因此需要在程序中设置密钥,
这样可以让Flask-WTF通过该密钥生成CSRF令牌,以便用CSRF令牌验证请求中表单数据的真伪。
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
return render_template('register_wtf.html', form=form)
#在templates文件夹中创建模板文件register_wtf.html,并在该模板文件中获取表单字段
<body>
<h1>注册页面</h1>
<form method="post">
{#获取username对应的标签名称#}
<span>{{ form.username.label }}</span><br>
{{ form.username }}<br> {#调用表单字段渲染为HTML#}
<span>{{ form.password.label }}</span><br>
{{ form.password }}<br>
<span>{{ form.password2.label }}</span><br>
{{ form.password2 }}<br>
<p>{{ form.submit }}</p>
</form>
</body>
则:app.py的完整代码如下:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length, EqualTo
from flask import render_template
app = Flask(__name__)
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
return render_template('register.html', form=form)
class RegisterForm(FlaskForm):
username = StringField(label='用户名:',
validators=[DataRequired(message='用户名不能为空'),
Length(3, 15, message='长度应该为3~15')])
password = PasswordField('密码:',
validators=[DataRequired(message='密码不能为空')])
password2 = PasswordField('确认密码:',
validators=[DataRequired(message='密码不能为空'),
EqualTo('password', message='两次密码不一致')])
submit = SubmitField('注册')
if __name__ == '__main__':
app.run()
register的完整代码如下:
<body>
<h1>注册页面</h1>
<form method="post">
{#获取username对应的标签名称#}
<span>{{ form.username.label }}</span><br>
{{ form.username }}<br> {#调用表单字段渲染为HTML#}
<span>{{ form.password.label }}</span><br>
{{ form.password }}<br>
<span>{{ form.password2.label }}</span><br>
{{ form.password2 }}<br>
<p>{{ form.submit }}</p>
</form>
</body>
得到注册页面为:
通过Flask-WTF验证表单
表单数据验证分为客户端验证和服务端验证
客户端验证是指客户端(浏览器)对用户提交的数据进行校验。客户端验证可以通过多种方式进行验证,包括使用HTML5内置的验证属性、JavaScript表单验证库等。客户端验证可以实时动态提示用户输入是否正确,只有用户输入正确后才会将表单数据发送给服务器。
服务器端验证是指用户把表单数据提交到服务器端,由服务器端对表单数据进行校验。在服务器端校验时,若出现错误,则会将错误信息加入到响应进行返回,待用户修改后再次提交表单数据,直至通过校验为止。
- Flask-WTF的FlaskForm类中提供了用于验证表单数据的validate_on_submit()方法,该方法内部会调用表单验证器对表单数据进行验证,具体看如下示例:
(1)app.py创建表单
class RegisterForm(FlaskForm):
username = StringField(label='用户名:', render_kw={'required': False},
validators=[DataRequired(message='用户名不能为空'),
Length(3, 15, message='长度应该为3~15')])
password = PasswordField('密码:', render_kw={'required': False},
validators=[DataRequired(message='密码不能为空')])
password2 = PasswordField('确认密码:', render_kw={'required': False},
validators=[DataRequired(message='密码不能为空'),
EqualTo('password', message='两次密码不一致')])
submit = SubmitField('注册')
(2)通过validate_on_submit()对表单数据进行验证
validate_on_submit()方法的返回值是一个布尔值,若返回值为True,则表示用户提交的表单数据符合验证器定义的规则,说明通过验证;若返回值为False,则用户提交的表单数据不符合验证器定义的规则,说明未通过验证。
针对未通过验证的情况,FlaskForm会将错误消息添加到表单类的errors属性中,errors属性的值是一个匹配表单字段类属性到错误信息列表的字典。若需要获取具体的错误信息列表,则可以在模板文件中通过“form.字段名. errors”进行获取。
app = Flask(__name__)
app.secret_key = '34sdfji9453#$@'
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
return '注册成功!'
return render_template('register_verification.html', form=form)
if __name__ == '__main__':
app.run()
(3) 在templates文件夹中创建模板文件register.html,并在该模板文件中获取表单字段
<form method="post">
{# 定义宏循环遍历错误信息列表#}
{% macro print_error(form_fields) %}
{% for error_message in form_fields %}
<p class="error" style="color: red;
display:inline;" >{{ error_message }}</p>
{% endfor %}
{% endmacro %}
<span>{{ form.username.label }}</span><br>
{{ form.username }}{{ print_error(form.username.errors) }}<br>
<span>{{ form.password.label }}</span><br>
{{ form.password }}{{ print_error(form.password.errors) }}<br>
<span>{{ form.password2.label }}</span><br>
{{ form.password2 }}{{ print_error(form.password2.errors) }}<br>
<p>{{ form.submit }}</p>
</form>