第四章 Web表单
序:在使用Flask表单前,需要下载安装拓展:Flask-WTF。win10下的安装为:pip install flask-wtf
⭐web表单是web应用程序的基本功能,它是HTML页面中负责数据采集的部件,表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。表单由3个部分组成:
- 表单标签
- 表单域
- 表单按钮
4.1跨站请求伪造保护
默认情况下,Flask-WTF能保护所有的表单免受跨站请求伪造的攻击。所谓的跨站请求伪造,即恶意网站把请求发送到被攻击者已登陆的其他网站时就会引发CSRF攻击。
为了实现CSRF保护,Flask-WTF需要程序设置一个密钥,Flask-WTF使用这个密钥生成加密令牌,再用加密令牌验证请求中表单数据的真伪。
app = Flask(__name__)
app.config['SECRET_KEY']='HARD TO GUESS STRING!'
⭐app.config字典可以用来存储框架,扩展和程序本身的配置变量,使用字典的语法就能把配置信息加入到app.config对象中。
4.2 表单类
使用Flask-WTF时,每个Web表单都有一个继承自Form的类表示。这个类定义表单中的一组字段,每个字段都用对象表示.字段的对象可以附属一个或多个验证函数。验证函数可以用来验证用户提交的输入值是否符合要求。
下例是一个简单的Web表单,包含一个文本字段和一个提交按钮:
from flask.ext_wtf import Form
from wtforms import StringField,SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('name:',validators=[Required()])
submit = SubmitField('Submit')
上述表单中的字段都定义为类变量,类变量的值是相应字段类型的对象。在这个示例中,NameForm表单中有一个名为name的文本字段和一个名为submit的提交按钮。StringField类表示属性为type=“text”的<input>元素。SubmitField类表示属性为type="submit"的<input>元素。字段构造函数的第一个参数是把表单渲染成HTML时使用的标号。
?StringField构造函数中的可选参数validators指定一个由验证函数组成的列表,在接受用户提交的数据之前验证数据。验证函数Required()确保提交的数据不为空。?
?除了文本字段,WTForms支持的HTML标准字段如下:
字段类型 | 说明 |
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文本字段 |
DateField | 文本字段,值为datetime.date格式 |
DateTimeField | 文本字段,值为datetime.datetime格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleanField | 文本字段,值为布尔值 |
RadioField | 一组单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表,可以选择多个值 |
FileField | 文件上传字段 |
SubmitField | 表单提交按钮 |
FormField | 把表单作为字段嵌入另一个表单 |
FieldList | 一组指定类型的字段 |
?WTForms验证函数一览
验证函数 | 说明 |
验证电子邮件地址 | |
EqualTo | 比较两个字段的值,常用于要求输入两次密码进行确认的情况 |
IPAddress | 验证IPv4网络地址 |
Length | 验证输入字符串的长度 |
NumberRange | 验证输入的值在验证范围内 |
Optional | 无输入值时跳过其他验证函数 |
Required | 确保字段中有数据 |
Regexp | 使用正则表达式验证输入值 |
URL | 验证URL |
AnyOf | 确保输入的值在可选列表里 |
NoneOf | 确保输入值不在可选值列表中 |
4.3 把表单渲染成HTML
表单字段是可以调用的,在模板中调用后会渲染成HTML。假设视图函数把一个Form实例通过参数form传入模板,在模板中可以生成一个简单的表单。
①.传统方式是在HTML模板中直接写form表单:
<form methods="post">
<label>用户名:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="Password"><br>
<label>确认密码:</label><input type="password" name="Password2"><br>
<input type="submit" value="提交"><br>
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
</form>
在视图函数中获取表单数据如下:
from flask import Flask,render_template,request
app=Flask(__name__)
@app.route('/wtf',methods=['GET','POST'])
def index_wtf():
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]):
print('参数不完整')
elif password != password2:
print('密码不一致')
else:
return 'success'
return render_template('wtf1.html')
if __name__ == '__main__':
app.run(debug=True)
?request.form能获取POST请求中提交的表单数据。
②.使用WTF实现表单:
from flask import Flask,render_template
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
app = Flask(__name__)
app.secret_key='bazinga'
class LoginForm(FlaskForm):
username = StringField('用户名')
password = PasswordField('密码')
password2 = PasswordField('确认密码')
submit = SubmitField('登陆')
@app.route('/form',methods=['GET','POST'])
def login():
login_form = LoginForm()
return render_template('wtf2.html',form=login_form)
if __name__ == "__main__":
app.run(debug=True)
对应的模板:
<form method="post">
{# 设置csrf_token #}
{{ form.csrf_token() }}
{{ form.username.lable }}{{ form.username }}<br>
{{ form.password.lable }}{{ form.password }}<br>
{{ form.password2.lable }}{{ form.password2 }}<br>
{{ form.submit }}<br>
⭐注意,使用Flask-WTF时要配置参数SECRET_KEY="自定义字符串(一般在不同程序中需要使用不同的密钥,并且保证不会被恶意者知道的密钥)"。
优化版登陆页面:
from flask import Flask,render_template,request,flash
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,EqualTo
app = Flask(__name__)
app.secret_key='bazinga'
class LoginForm(FlaskForm):
username = StringField('用户名',validators=[DataRequired()])
password = PasswordField('密码',validators=[DataRequired()])
password2 = PasswordField('确认密码',validators=[DataRequired(),EqualTo('password','密码不一致')])
submit = SubmitField('登陆')
@app.route('/form',methods=['GET','POST'])
def login():
login_form = LoginForm()
if request.method == 'POST':
#request.form能获取POST请求中提交的表单数据
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
if login_form.validate_on_submit():
print(username,password)
return 'success'
else:
flash('error')
#return 'error'
return render_template('wtf2.html',form=login_form)
if __name__ == "__main__":
app.run(debug=True)
模板同优化前模板一样。
4.4 Flash消息
请求完成后,有时候需要让用户知道状态发生了变化,这时可以使用确认消息,警告或者错误消息。这时flash()函数就可以实现这种效果。
仅仅调用flash()函数并不能把消息显现出来,程序使用的模板要渲染这些消息。最好在基模板中渲染这些flash消息,因为这样可以使所有的页面都能使用这些消息。flask把get_flashed_messages()函数开放给模板并渲染消息。