介绍:
Flask-WTF 提供了简单地 WTForms 的集成。
WTForms是一个灵活的表单验证和渲染库,用于Python Web开发。它可以与您选择的任何Web框架和模板引擎一起使用。它支持数据验证、CSRF 保护、国际化 (I18N) 等。有各种社区库提供了与流行框架的更紧密集成。
为什么要用WTF,WT Forms是用于提供用户界面的灵活的表单呈现和验证库
WTForms文档:https://wtforms.readthedocs.io/en/3.0.x/ Flask-WTF文档:http://www.pythondoc.com/flask-wtf/
用 pip 安装 Flask-WTF 是十分简单的:
pip install Flask-WTF
该模块包含一个Form类, 该类被视为所有与表单相关的操作的父类。
一、具体实现案例:
1、创建表单类
内容:主要为页面输入中各种规则的显示
"""
@File: formtest.py
"""
import re
from flask_wtf import FlaskForm
from flask_wtf.file import FileRequired, FileField, FileAllowed
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, ValidationError, EqualTo
"""
从 0.9.0 版本开始,Flask-WTF 将不会从 wtforms 中导入任何的内容.
用户必须自己从 wtforms 中导入字段。
"""
class UserForm(FlaskForm):
name = StringField(label='用户名',
validators=[DataRequired(),
Length(min=6,max=12,
message='用户名长度必须在6到12位之间')
]
)
phone = StringField(label='手机号码',
validators=[DataRequired(),
Length(min=11, max=11,
message='手机号码必须是11位数字')
]
)
password = PasswordField(label='密码',
validators=[DataRequired(),
Length(min=6, max=12,
message='密码长度必须在6到12位之间')
]
)
repassword = PasswordField(label='确认密码',
validators=[DataRequired(),
Length(min=6, max=12,
message='密码长度必须在6到12位之间'),
EqualTo('password', '两次密码不一致')
]
)
user_img = FileField(label='用户头像',
validators=[FileRequired(),
FileAllowed(['jpg', 'png', 'jpeg'],
message='用户头像必须是图片格式')
]
)
def validate_name(self, data):
print('---->>>', self.name.data, '==', data.dta)
if self.name.data[0].isdigit():
raise ValidationError('用户名不能以数字开头')
def validate_phone(self, data):
"""校验手机号"""
phone = data.data
if not re.search(r'^1[35678]\d{9}', phone):
raise ValidationError('手机号码格式错误!')
FlaskForm类中的源码部分 Form对象调用validate函数时会自动寻找validate_{name}的方法添加到验证序列,并在原先字段的验证序列验证完毕后执行。
2、视图中使用
这里涉及到了CSRF保护,可查看后面文章
"""
@File: app.py
"""
import os
from flask import Flask, render_template, make_response
from flask_wtf import CSRFProtect
from werkzeug.utils import secure_filename
from formtest import UserForm
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hsdkfhksd'
app.config['ENV'] = 'development'
csrf = CSRFProtect(app=app)
@app.route('/home', methods=['GET', 'POST'])
def home():
uform = UserForm()
if uform.validate_on_submit():
"""注意:
1、不需要把 request.form 传给 Flask-WTF;Flask-WTF 会自动加载。
2、validate_on_submit 将会检查是否是一个 POST 请求并且请求是否有效。
"""
name = uform.name.data
password = uform.password.data
phone = uform.phone.data
user_img = uform.user_img.data
filename = secure_filename(user_img.filename)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_DIR = os.path.join(BASE_DIR, 'static')
STATIC_DIR = os.path.join(STATIC_DIR, 'upload')
user_img.save(os.path.join(STATIC_DIR, filename))
return '这是一个post请求,提交成功'
return render_template('user.html', uform=uform)
if __name__ == '__main__':
app.run()
CSRF跨站请求伪造,源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。
如果网站没有通过CSRF验证,都会返回400响应
3、模版中的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户页面</title>
<style>
p span {
color: red;
font-size: 14px;
}
</style>
</head>
<body>
<form action="{{ url_for('home') }}" method="post" enctype="multipart/form-data">
<p>{{ uform.csrf_token }}</p>
<p>{{ uform.hidden_tag() }}</p>
<p>{{ uform.name.label }}: {{ uform.name }}
<span>{% if uform.name.errors %} {{ uform.name.errors.0 }} {% endif %} </span>
</p>
<p>{{ uform.password.label }}: {{ uform.password }}
<span>{% if uform.password.errors %} {{ uform.password.errors.0 }} {% endif %} </span>
</p>
<p>{{ uform.repassword.label }}: {{ uform.repassword }}
<span>{% if uform.repassword.errors %}{{ uform.repassword.errors.0 }}{% endif %} </span>
</p>
<p>{{ uform.phone.label }}: {{ uform.phone }}
<span>{% if uform.phone.errors %}{{ uform.phone.errors.0 }}{% endif %} </span>
</p>
<p>{{ uform.user_img.label }}: {{ uform.user_img }}
<span>{% if uform.user_img.errors %}{{ uform.user_img.errors.0 }}{% endif %} </span>
</p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
4、运行后访问查看提示
这里输入框还可以使用bootstrap美化下,这里就不写了…
-
这种是自定义的校验报错显示(def validate_name: …) -
这种是不符合验证器的提示 (validators)
二、总结:
1、视图中使用:
from test import UserForm
def xxxx():
uform = UserForm()
......
return render_template('user.html',uform=uform)
2、模板中使用:
<form action="/" method="post">
{{ uform.csrf_token }}
{{ uform.hidden_tag() }}
{{ uform.name }} {{ uform.name.error.0 }}
{{ uform.password }} {{ uform.password.error.0 }}
<p><input type="submit" value="提交"></p>
</form>
3、验证是否是一个POST,并且是否有效:validate_on_submit()
@app.route('/', methods=['GET','POST'])
def test():
uform = UserForm()
if uform.validate_on_submit():
return '这是一个post请求'
return render_template('user.html', uform=uform)
4、在自定义表单类中,还有其他Filed类型、和各种验证
4.1 各种Filed字段类型
class UserForm(FlaskForm):
name = StringField(label='用户名',
validators=[DataRequired(),
Length(min=6, max=12)
]
)
__all__ = (
"BooleanField",
"TextAreaField",
"StringField",
"PasswordField",
"FileField",
"MultipleFileField",
"HiddenField",
"SearchField",
"SubmitField",
"TelField",
"URLField",
"EmailField",
)
4.2 各种的验证:
repassword = PasswordField(label='确认密码',
validators=[DataRequired(),
Length(min=6, max=12),
EqualTo('password', '两次密码不一致')
]
)
__all__ = (
"DataRequired",
"data_required",
"Email",
"email",
"EqualTo",
"equal_to",
"IPAddress",
"ip_address",
"InputRequired",
"input_required",
"Length",
"length",
"NumberRange",
"number_range",
"Optional",
"optional",
"Regexp",
"regexp",
"URL",
"url",
"AnyOf",
"any_of",
"NoneOf",
"none_of",
"MacAddress",
"mac_address",
"UUID",
"ValidationError",
"StopValidation",
)
|