🌴 表单
1、表单介绍
当我们在网页上填写账号密码进行登录的时候,就是在填写一个“表单”。web表单是web应用程序种最基本的功能。
2、表单的简单实现
下面的代码实现了这样的功能:
- 前端发起请求时,收到一个含表单的网页
- 在网页填写表单提交到后端
- 后端对表单进行验证,显示成功或错误信息到前端
网页显示:
1. 代码
前端代码(index2.html):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!-- 一个表单 --> <form method="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> </body> </html>
后端代码(python):
from flask import Flask, render_template, request, flash app = Flask(__name__) app.secret_key = 'qfmz' ''' 目的:实现一个简单的登录的逻辑处理 1. 路由需要有get和post两种请求方式 --> 需要判断请求方式 2. 获取请求的参数 3. 判断参数是否填写 & 密码是否相同 4. 如果判断都没有问题,就返回一个success ''' ''' 给模板传递消息 flash --> 需要对内容加密,因此设置secret_key,做加密消息的混淆 模板中遍历消息 ''' @app.route('/', methods=['GET', 'POST']) def index(): # request: 请求对象 --> 获取请求方式、数据 # 1. 判断请求方式 if request.method == 'POST': # 2. 获取请求参数 username = request.form.get('username') password = request.form.get('password') password2 = request.form.get('password2') print(username) print(password) print(password2) # 3. 判断参数是否填写 & 密码是否相同 if not all([username, password, password2]): flash('参数不完整') elif password != password2: flash('密码不一致') else: return 'success' # 2. 获取请求参数 return render_template('index2.html') app.run(debug=True)
2. 代码的执行逻辑
我填写一个表单时,这些代码的执行逻辑是怎样的呢?我知道这些代码能跑,但我总感觉自己和这些代码之间的隔阂较大,我不知道我在网页中的没一步操作是哪些代码在发挥作用。对此,debug单步执行是一个很有用的帮助理解的办法。
我知道,一个请求就对应着一个响应。那么总结下,进入一个网页,填写和提交表单的过程中应该是发生了2次请求,同时也有2次响应。
- 第1次,我进入网页,网页对后端发送GET请求,后端判断请求类型不是POST,于是直接返回(不是返回html源代码,是在flask的模板引擎里走了一遭的)
index2.html
,前端就显示一个需要填写的表单。
第2次,我填写完表单进行提交后,网页将表单中填写的数据作为参数,对后端发送POST请求,使用webob库解析environ得到的post参数如下:
MultiDict([('username', '1'), ('password', '******'), ('password2', '******')])
- 然后后端根据请求再返回一个网页到前端。
3、使用wtf扩展实现
显示效果与前面的“简单实现”一样,前端代码写起来会简单一些,后端的表单逻辑验证也可以直接使用库实现。
前端代码(index.html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post"> {{ form.csrf_token() }} {{ form.username.label }}{{ form.username }}<br> {{ form.password.label }}{{ form.password }}<br> {{ form.password2.label }}{{ form.password2 }}<br> {{ form.submit }} <!-- 使用遍历获取闪现的消息 --> {% for message in get_flashed_messages() %} {{ message }} {% endfor %} </form> </body> </html>
后端代码(python)
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 = 'qfmz' ''' 使用WTF实现表单 自定义表单类 ''' class LoginForm(FlaskForm): username = StringField('用户名', validators=[DataRequired()]) password = PasswordField('密码', validators=[DataRequired()]) password2 = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', '密码填入不一致!')]) submit = SubmitField('提交') @app.route('/', methods=['GET', 'POST']) def login(): login_form = LoginForm() # 1. 判断请求方式 if request.method == 'POST': # 2. 获取请求参数 username = request.form.get('username') password = request.form.get('password') password2 = request.form.get('password2') # 3. 逻辑验证,WTF一句话 # 自动包含CSRF_token验证,前端代码记得写上{{ form.csrf_token() }} if login_form.validate_on_submit(): print(username, password, password2) return 'success' else: flash('填写错误,请确保每项都填,且两次密码填写一致。') return render_template('index.html', form=login_form) app.run(debug=True)
4、bug记录:表单验证总是失败
起初没加csrf时,以为是它的原因;后来加了还是失败,总以为是我csrf没写好,在网上搜csrf相关的文章和教程,然而令我没想到的是,最终问题是在验证函数EqualTo()
这里,
# 问题代码 password2 = PasswordField('确认密码', validators=[DataRequired(), EqualTo(password, '密码填入不一致!')]) # 修改 password2 = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', '密码填入不一致!')])