我们使用django时一般都会用用到django自带的form组件进行登录注册的验证,非常的好用也很强大。flask中同样也有类似的form组件,叫flask-wtf,名字不是很好听,但是功能还是一样的强大。flask-wtf是属于第三方库,需要安装:pip intsall flask-wtf
。
flask-wtf的使用和django的Form基本类似。
首先创建一个form.py的文件,当然也可以直接将form类写在视图文件里。
from flask_wtf import FlaskForm # 用来定义表单的父类
import wtforms # 可以用来定义字段以及进行表单验证,类似django中的forms
表单常用的字段:
# StringField 字符串
# IntegerField 整型
# TextAreaField 文本
# PasswordField 密码
# HiddenField 隐藏域
# DateField Datatime.data格式 年月日
# DateTimeField Datatime.datatime格式 年月日 时分秒
# FloatField 小数
# RadioField 单选
# SelectField 下拉
# FileField 文件
# SubmitField 提交
表单字段常用参数:
# label = None 字段的标签,即input框前的提示名
# validators = None 用来储存各种验证器的列表,验证表单数据时会逐一进行调取
# filters = tuple() 过滤
# description = '' 字段描述,常用与帮助文档,类似django的django的help_text
# id = None 为字段添加id值,默认为id为字段名
# default = None 是一个字符串或可调用对象,为表单字段设置默认值,选择框常用
# widget = None html控件,用来定义input框的类型,需要导入widgets
# render_kw = None 用来设置input框的属性
Validator常用校验:
# Email 邮件校验
# EqualTo 比较两个字段的值,常用于密码比较
# IPAdress Ipv4格式的IP地址
# length 长度
# NumberRange 数字范围
# DataRequired 空值检查
# Url 验证是否符合url格式
# AnyOf 确保输入值在指定范围
# NoneOf 确保输入的值不在范围
django中可以自定义验证规则,flask-wtf中也不例外,我们可以使用validate_(字段名)
进行验证。FlaskForm中还有一些内置的方法,
源码如下:
def wrap_formdata(self, form, formdata):
if formdata is _Auto:
if _is_submitted():
if request.files:
return CombinedMultiDict((
request.files, request.form
))
elif request.form:
return request.form
elif request.get_json():
return ImmutableMultiDict(request.get_json())
return None
def is_submitted(self):
"""Consider the form submitted if there is an active request and
the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
"""
return _is_submitted()
def validate_on_submit(self):
"""Call :meth:`validate` only if the form is submitted.
This is a shortcut for ``form.is_submitted() and form.validate()``.
"""
return self.is_submitted() and self.validate()
def hidden_tag(self, *fields):
"""Render the form's hidden fields in one call.
A field is considered hidden if it uses the
:class:`~wtforms.widgets.HiddenInput` widget.
If ``fields`` are given, only render the given fields that
are hidden. If a string is passed, render the field with that
name if it exists.
.. versionchanged:: 0.13
No longer wraps inputs in hidden div.
This is valid HTML 5.
.. versionchanged:: 0.13
Skip passed fields that aren't hidden.
Skip passed names that don't exist.
"""
def hidden_fields(fields):
for f in fields:
if isinstance(f, string_types):
f = getattr(self, f, None)
if f is None or not isinstance(f.widget, HiddenInput):
continue
yield f
return Markup(
u'\n'.join(text_type(f) for f in hidden_fields(fields or self))
)
wrap_formdata:获取request中的form数据并返回
is_submitted:判断是否有请求。
validate_on_submit:调用is_submitted()方法和validate()方法,判断表单是否通过验证并且提交,返回一个bool值。
hidden_tag:获取表单的隐藏字段。
使用flask-wtf进行登录验证:
form.py:
from flask_wtf import FlaskForm # 用来定义表单的父类
import wtforms # 可以用来定义字段以及进行表单验证,类似django中的forms
from myblog.models import db,Admin
import hashlib
def setPassword(password): # 密码加密
md5 = hashlib.md5()
md5.update(password.encode())
f_md5 = md5.hexdigest()
md5.update(f_md5.encode())
return md5.hexdigest()
class LoginForm(FlaskForm):
username = wtforms.StringField(
label="用户名",
widget=wtforms.widgets.TextInput(),
validators=[
wtforms.validators.DataRequired("用户名不可以为空!"),
wtforms.validators.Length(8,18,message="用户名必须在8-18位之间!")
]
)
password = wtforms.PasswordField(
label="密码",
widget=wtforms.widgets.PasswordInput(),
validators=[wtforms.validators.DataRequired("密码不可以为空!")]
)
def validate_username(self,field):
if Admin.query.filter_by(username=field.data).first():
password = setPassword(self.password.data)
if password != Admin.query.filter_by(username=field.data).first().password:
raise wtforms.ValidationError("您输入的用户名或密码错误!")
else:
raise wtforms.ValidationError("您输入的用户名或密码错误!")
后台代码:
import hashlib
from myblog.views.form import LoginForm
# cookie加密
def setUsername(username):
md5 = hashlib.md5()
md5.update(username.encode())
return md5.hexdigest()
# 后台登录
@backstage.route("/login/",methods=["get","post"])
def login():
form = LoginForm()
if form.validate_on_submit():
response = redirect("/backstage/")
username = setUsername(form.username.data)
response.set_cookie("username",username)
return response
return render_template("backstage/login.html",**locals())
前端代码:
<form method="post" action="/login/" novalidate>
{{ form.csrf_token }} # 添加csrf_token
<table >
<tr>
<th>{{ form.username.label }}:th>
<td>{{ form.username }}td>
tr>
<tr>
<th>{{ form.password.label }}:th>
<td>{{ form.password }}td>
tr>
table>
<div style="color: red"> # 错误信息展示
{% for error in form.errors.username %}
<p>{{ error }}p>
{% endfor %}
{% for error in form.errors.password %}
<p>{{ error }}p>
{% endfor %}
div>
<input style="margin-left: 12%" type="submit" value="登录">
form>