Form表单,在Web应用中无处不在。比如:用户登录表单,用户注册表单。
如果有个框架能够将这些共性抽象出来,那就能大量简化我们的工作。Python的WTForms就提供了这些功能。这里我们就结合Flask的WTForms扩展。Flask-WTF,来介绍如何在Web应用中制作表单。
安装和启用:
pip install Flask-WTF
WTForms让我们在后端代码中定义表单类,并列出表单的字段和相应的验证规则。下面是定义的一个MyForm类:
from flask_wtf import Form
from wtforms import StringField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
email = StringField(u'邮箱', validators=[
DataRequired(message= u'邮箱不能为空'), Length(1, 64),
Email(message= u'请输入有效的邮箱地址,比如:username@domain.com')])
password = PasswordField(u'密码',
validators=[Required(message= u'密码不能为空')])
submit = SubmitField(u'登录')
表单域类型 | 描述 |
---|---|
StringField | 文本框 |
TextAreaField | 多行文本框 |
PasswordField | 密码输入框 |
HiddenField | 隐藏文本框 |
DateField | 接收给定格式datetime.date型的文本框 |
DateTimeField | 接收给定格式datetime.datetime型的文本框 |
IntegerField | 接收整型的文本框 |
DecimalField | 接收decimal.Decimal型的文本框 |
FloadField | 接收浮点型的文本框 |
BooleanField | 带有True和False的复选框 |
RadioField | 一组单选框 |
SelectField | 下拉选择框 |
SelectMultipleField | 下拉多选框 |
FileField | 文本上传框 |
SubmitField | 表单提交按钮 |
FormField | 将一个表单作为表单域嵌入到容器表单中 |
FieldList | 给定类型的表单域列表 |
验证规则 | 说明 |
---|---|
DataRequired | 验证必填项 |
验证邮件地址格式 | |
EqualTo | 验证必须同另一个字段值相同,它需要传入另一个字段的名称“fieldname” |
Length | 验证输入字符串长度,它有两个参数:min最小长度,max最大长度,缺省的话就不检查 |
NumberRange | 验证输入数值的范围,它有两个参数:min最小长度,max最大长度,缺省的话就不检查 |
URL | 验证URL格式 |
IPAddress | 验证IP地址格式,默认IPV4,你可以传入‘ipv6=True’来验证IPV6地址 |
MacAddress | 验证Mac地址格式 |
AnyOf | 传入一个列表作为参数,验证是否匹配类表中的任一值 |
NoneOf | 传入一个列表作为参数,验证是否与列表中的所有值都不同 |
Regexp | 正则表达式验证,需传入一个正则表达式,它还有一个flags参数,如果你传入‘re.IGNORECASE’,就会忽略大小写 |
@app.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
email = form.email.data
...
return render_template('login.html', form=form)
点击了表单上的提交按钮时,form.validate_on_submit()判断会做下面两件事情:
也可以在表单类中创建自定义的验证函数,举个简单的例子;
自定义函数以validate_ + “要验证的属性名称”,比如要验证username,我们的自定义验证函数应为:validate_username
def validate_username(self, field):
# field.data是用户输入的数据。
if field.data == 'admin':
# ValidationError从wtforms导入,用来向用户显示错误信息,
# 验证函数的名称由validate_fieldname组成。
raise ValidationError('超级管理员已被注册,换一个吧。')
我们也可以在这里对用户数据进行预处理:
如果网址不是http开头,就转为http网址:
# 这个函数对用户输入的网址进行处理(字段名为website)。
def validate_website(self, field):
if field.data[:4] != "http":
field.data = "http://" + field.data
验证通过之后:
form.email.data
form.data[‘email’]
<form method="POST" action="/login/">
{{ form.hidden_tag() }}
{{ form.user.label }}: {{ form.user(size=20) }}
<input type="submit" value="Submit">
</form>
主程序app.py
from flask import Flask, render_template, flash
from forms import LoginForm,RegisterForm
from flask_bootstrap import Bootstrap
app = Flask(__name__)
# 设置配置
app.config.from_pyfile('config.py')
# 实例化bootstrap对象
bootstrap = Bootstrap(app)
@app.route('/login/',methods=['GET','POST'])
def login():
# 实例化表单对象
form = LoginForm()
# 1). 判断是否为post方法提交数据
# 2). 是否通过验证函数
if form.validate_on_submit():
# 获取表单数据(内容)
email = form.email.data
password = form.password.data
if email == 'westos@qq.com' and password == 'westos':
flash("登录成功")
return '登录成功'
else:
# flash('登录失败')
# return render_template('login.html')
return '登录失败'
else:
# 将form表单传递给html,按照表单的规则进行验证
return render_template('bs_login.html',form=form)
@app.route('/register/',methods=['GET','POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
return '获取性别%s' %(form.gender.data)
else:
return render_template('register.html',form=form)
# def register():
# return '注册'
@app.route('/')
def index():
return 'hello'
if __name__ == '__main__':
app.run()
配置文件config.py
SECRET_KEY = 'WESTOS'
表单文件forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, SelectField, RadioField
from wtforms.validators import DataRequired, Email, Length, EqualTo, Regexp, ValidationError
class LoginForm(FlaskForm):
email = StringField(label='电子邮箱',
validators=[
DataRequired(message='邮箱不能为空'),
Length(1,15, message='长度不符合条件'),
Email(message='请输入有效的邮箱地址,比如username@domain.com')
])
password = PasswordField(label='密码',
validators=[
DataRequired(message='密码不能为空')])
submit = SubmitField('登录')
class RegisterForm(FlaskForm):
name = StringField(
label='用户名',
validators=[DataRequired(message='用户名不能为空'),
Length(5,12,message='用户名长度必须在5-12之间')]
)
password = PasswordField(
label='密码',
validators=[DataRequired(),
Length(6,16,message='密码格式不正确')]
)
repassword = PasswordField(
label='确认密码',
validators=[DataRequired(),
# 验证当前表单输入密码和password表单输入密码是否一致,如果不一致,报错
EqualTo('password',message='密码不一致')]
)
email = StringField(
label='邮箱',
validators=[
DataRequired(),
Email(message='邮箱格式错误')
]
)
phone = StringField(
label='电话号码',
validators=[
DataRequired(),
Regexp(r'1\d{10}',message='电话号码格式错误')
]
)
# 下拉单选框
gender = SelectField(
label='性别',
# 填写的信息传入后台的类型
coerce=int,
# 下拉列表的选项
choices=[(1,'男'),(2,'女')]
)
# # 下拉多选框
tech = SelectMultipleField(
label='擅长领域',
coerce=int,
choices=[(1,'python'),(2,'linux'),(3,'php'),(4,'java')]
)
def validate_name(self,field):
# field.data是用户输入的数据
if field.data == 'admin':
# ValidationError用来向用户显示错误信息
# 验证的函数的名称由validate_fieldname组成
raise ValidationError('超级管理员已经被注册,换一个吧')
submit = SubmitField(label='注册')
login页面:login.html
通过form表单格式编写页面,代码简洁明了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% for message in get_flashed_messages() %}
<p style="color: red">{{ message }}</p>
{% endfor %}
<form action='/login/' method="POST">
{# <input type="email" name="email" placeholder="email"><br>#}
{# <input type="password" name="password" placeholder="password"><br>#}
{# <input type="submit" value="登录">#}
{# 显示报错信息#}
{# {{ form.email.errors }} #}
{{ form.hidden_tag() }}
{{ form.email.label }}{{ form.email()}}{{ form.email.errors }}
{{ form.password.label }}{{ form.password() }}{{ form.password.errors }}
{{ form.submit() }}
</form>
</body>
</html>
注册页面register.html
通过wtf.quick_form(form)快速实现页面:
{#导入bootstrap的基模板,自动加载css样式和js动效#}
{% extends "bootstrap/base.html" %}
{#导入html代码,并起别名#}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}
注册
{% endblock %}
{% block content %}
<div style="width:70%; margin: 0 auto">
<h1>用户注册</h1>
<hr/>
{# 传入表单对象#}
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
详细代码可以:点击这里,包含css,js静态文档和其余html页面。