Python学习笔记(6.3.10 flask-wtf数据验证)
前言:本文是学习网易微专业的《python全栈工程师 - Flask高级建站》课程的笔记,欢迎学习交流。同时感谢老师们的精彩传授!一、课程目标
- 表单数据接收
- 内置数据验证器
- 错误消息
- 自定义验证器
form
表单提交的数据可以使用form.data
接收form = LoginForm()
username = form.data['username']
form.data
会对表单提交的数据进行验证,数据转换如果有一个表单字段是
Integer
类型,比如score
,那么:score = form.data['score']
相当于:
if "score" in request.form:
score = int(request.form['score'])
else:
score = 0
实操:
step
:修改app.py
文件中的login()
视图函数:.
.
.
@app.route('/login', methods=['get', 'post'])
def login():
# 新增
form = LoginForm()
message = None
if request.method == "POST":
# 用户名和密码的数据接收用下面这两行代替
username = form.data['username']
password = form.data['password']
user = User.query.filter_by(username=username).first()
if user and user.validate_password(password):
session['user'] = user.username
# 登录成功返回首页
return redirect(url_for("index"))
else:
message = "用户名与密码不匹配"
return render_template("login.html", message = message,
form=form
)
.
.
.
2.2.数据验证器 2.2.1.数据验证的必要性 【Python学习笔记(6.3.10 flask-wtf数据验证)】为什么要进行验证?
1.用户填写的时候不了解数据要求
2.别有用心的用户不择手段危害网站
验证手段:
1.前端验证,改进用户体验
2.后端验证,提升网站安全性
由于前端的任何验证都可以被忽略,所以永远不要相信前端提交来的数据是安全的。
2.2.2.flask-wtf提供的数据验证
验证器 | 说明 |
---|---|
InputRequire(message) | 必填字段 |
Length(min, max, message) | 输入长度范围 |
NumberRange(min, max, message) | 输入数值范围 |
Regexp(regex, flags, message) | 正则表达式验证 |
Url(message) | 输入字符串为合法的网址结构 |
Email(message) | 输入必须为邮件地址 |
EqualTo(fieldname, message) | 必须与fieldname的值一致 |
DateRequired(message) | 输入有效性 |
FileRequired(message) | 必须是文件 |
AnyOf(values, message) | 输入值必须在values列表中 |
NoneOf(values, message) | 输入值不在values列表中 |
修改
forms/account_form.py
文件中的LoginForm()
为以下代码:from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, \
widgets, RadioField, TextAreaField,SelectFieldfrom flask_ckeditor import CKEditorField
# 引入DataRequired模块
from wtforms.validators import DataRequiredclass LoginForm(FlaskForm):
# 用户名和密码新增validtors验证器
username = StringField('用户名',
validators=[DataRequired(message="必须填写用户名")],
render_kw={"class": "form-control", "placeholder": "输入用户名"})
password = PasswordField('密码',
validators=[DataRequired(message="必须填写密码")],
render_kw={"class": "form-control", "placeholder": "输入密码"})
# 多选框选项
choices = [(1, "一周免登录"), (2, "二周免登录"), (3, "三周免登录")]
remember = CheckBoxField('记忆方式', choices=choices)
sex_choices = [(1, '女'), (2, '男')]
sex = RadioField('性别', choices=sex_choices)
# 这里第一个参数为空,因为登录按钮不用显示label的值
submit = SubmitField('', render_kw={"class": "btn btn-default", "value": "立即登录"})
.
.
.
经过以下修改后,用户登录表单的用户名和密码输入框就会多个
required
属性。2.3.数据验证与错误显示 2.3.1.数据验证在视图函数中验证
form = LoginForm()
# if request.method == 'POST':
# 只有数据验证通过才会执行
if form.validator_on_submit():
pass
else:
print(form.errors)
2.3.2.表单错误输出 可以在前端页面中进行错误的输出显示,显示格式取决于前端设计。比如这里:
![Python学习笔记(6.3.10 flask-wtf数据验证)](https://img.it610.com/image/info8/58eeebae6c2b400f938dd3c49fac3de0.jpg)
文章图片
实操:
Step1
:替换forms/account_form.py
文件中的LoginForm()
为下面代码:.
.
.
# 引入Length
from wtforms.validators import DataRequired, Length
.
.
.
class LoginForm(FlaskForm):
# 在验证器里新增Lenth长度验证
username = StringField('用户名',
validators=[DataRequired(message="必须填写用户名"),
Length(min=15, max=25, message="用户名长度6~15")],
render_kw={"class": "form-control", "placeholder": "输入用户名"})
password = PasswordField('密码',
validators=[DataRequired(message="必须填写密码")],
render_kw={"class": "form-control", "placeholder": "输入密码"})
# 多选框选项
choices = [(1, "一周免登录"), (2, "二周免登录"), (3, "三周免登录")]
remember = CheckBoxField('记忆方式', choices=choices)
sex_choices = [(1, '女'), (2, '男')]
sex = RadioField('性别', choices=sex_choices)
# 这里第一个参数为空,因为登录按钮不用显示label的值
submit = SubmitField('', render_kw={"class": "btn btn-default", "value": "立即登录"})
.
.
.
Step2
:修改app.py
文件中的login()
视图函数为下面代码:.
.
.
@app.route('/login', methods=['get', 'post'])
def login():
form = LoginForm()
message = None
# 原来的判断是否是post,改为下面这个验证判断
if form.validate_on_submit():
username = form.data['username']
password = form.data['password']
user = User.query.filter_by(username=username).first()
if user and user.validate_password(password):
session['user'] = user.username
# 登录成功返回首页
return redirect(url_for("index"))
else:
message = "用户名与密码不匹配"
else:
print(form.errors)
return render_template("login.html", message = message,
form=form
)
.
.
.
Step3
:修改templates/login.html
:.
.
.
.
.
.
2.4.自定义数据验证器 2.4.1.内联验证器 内联验证器直接与字段绑定,在
form
定义类中定义:class LoginForm(FlaskForm):
username = StringField("用户名", validators=[DataRequired()],...)
# 为usename定义一个验证器
def validate_username(form, field):
if field.data.find("admin") != -1:
raise ValidationError("不能包含敏感字")
实操:
Step1
:修改forms/account_form.py
文件中的注册表单部分内容:.
.
.
# 引入ValidationError模块
from wtforms.validators import ValidationError
# 注册表单
class RegisterForm(FlaskForm):
name = StringField('真实姓名',
render_kw={"class": "form-control", "placeholder": "请填写真实姓名"})
username = StringField('用户名',
validators=[DataRequired(message="必须填写用户名")],
render_kw={"class": "form-control", "placeholder": "请填写用户名"})
password = PasswordField('密码',
render_kw={"class": "form-control", "placeholder": "请填写密码"})
confirmpassword = PasswordField('确认密码',
render_kw={'class': 'form-control', "placeholder": "请填写确认密码"})
# 这里要加上coerce = int,不然会报错:Not a valid choice
sex = RadioField('选择性别',
choices=[(1, '男'), (0, '女')]
)
like = CheckBoxField('选择爱好',
choices=[(1, '钓鱼'), (2, '游泳'), (3, '看书'), (4, '旅游')],
render_kw={"class": "checkbox-inline"})
city = SelectField('选择城市', choices=[
('010', '北京'),
('021', '上海'),
('0512', '苏州'),
], render_kw={"class": "form-control"})
intro = TextAreaField('简介')
submit = SubmitField('', render_kw={"class": "btn btn-default", "value": "立即注册"}) # 新增内联验证器,验证用户名是否包含admin字符串
def validate_username(self, field):
# 查找用户名是否包含admin字符串
if field.data.find("admin") != -1:
raise ValidationError('不能包含敏感字')
Step2
:修改views/users.py
中的register()
视图函数:.
.
.
# 引入 RegisterForm 注册表单模块
from forms.account_form import RegisterForm
user_app = Blueprint("user_app", __name__)@user_app.route("/register", methods=['get','post'])
def register():
# 实例化注册表单
form = RegisterForm()
message = None
# 这里改为验证器提交判断,数据接收都改为form.data[]
if form.validate_on_submit():
if validate_username(form.data['username']):
return render_template("user/register.html", message="用户名重复")realname = form.data['name']
username = form.data['username']
password = form.data['password']
sex = form.data['sex']
mylike= '|'.join(form.data['like'])
city= form.data['city']
intro= form.data['intro']user = User(
realname=realname,
username=username,
sex=sex,
mylike=mylike,
city=city,
intro=intro
)# 密码加密
user.hash_password(password)
try:
db.session.add(user)
db.session.commit()
return redirect(url_for('login'))
except Exception as e:
message = "注册失败:" + str(e)
else:
print(form.errors)
# 将form 注册表单传给前端模版
return render_template("user/register.html", message=message, form=form)
.
.
.
Step3
:替换templates/user/register.html
内容为以下代码:{% extends "base.html" %}
{% block content %}
用户注册
{% if message %}
{{ message }}
{% endif %}
{%endblock %} {% block footer %}{{ super() }}
src="https://www.it610.com/article/{{ url_for('static', filename='ckeditor/ckeditor.js') }}">
{{ ckeditor.config(name="intro")}}
{% endblock %}