表单处理
基本表单处理:使用 request.form 获取表单数据。
使用 Flask-WTF:结合 WTForms 进行表单处理和验证,简化表单操作。
表单验证:使用验证器确保表单数据的有效性。
文件上传:处理文件上传和保存文件。
CSRF 保护:确保表单免受跨站请求伪造攻击。
基本表单处理 form.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <!DOCTYPE html > <html > <head > <title > Form Example</title > </head > <body > <form action ="/submit" method ="post" > <label for ="name" > Name:</label > <input type ="text" id ="name" name ="name" > <br > <label for ="email" > Email:</label > <input type ="email" id ="email" name ="email" > <br > <input type ="submit" value ="Submit" > </form > </body > </html >
app.py
1 2 3 4 5 6 7 8 9 @app.route('/form' ) def form (): return render_template('form.html' ) @app.route('/submit' , methods=['POST' ] ) def submit (): name = request.form.get('name' ) email = request.form.get('email' ) return f'Name: {name} , Email: {email} '
request.form.get('变量名')
,变量名是input
中的name
字段的值
使用 Flask-WTF 扩展 Flask-WTF 是一个封装了 WTForms 的扩展,提供了表单处理和验证的功能,使得表单处理更加简洁和强大。
安装 Flask-WTF 1 2 3 pip install flask-wtf # 我的设备上有Python2.7和Python3,给Python3安装所以用以下的命令 # pip3 install flask-wtf
app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from flask import Flask, render_template, redirect, url_forfrom flask_wtf import FlaskFormfrom wtforms import StringField, EmailField, SubmitFieldfrom wtforms.validators import DataRequired, Emailapp = Flask(__name__) app.secret_key = '6a31ad17a15b0d887049fcfd478aedeb8da2d40049f1413ca4add757379d4237' class MyForm (FlaskForm ): name = StringField('Name' , validators=[DataRequired()]) email = EmailField('Email' , validators=[DataRequired(), Email()]) submit = SubmitField('Submit' ) @app.route('/form' , methods=['GET' , 'POST' ] ) def form (): form = MyForm() if form.validate_on_submit(): name = form.name.data email = form.email.data return f'Name: {name} , Email: {email} ' return render_template('form.html' , form=form) if __name__ == '__main__' : app.run(debug=True )
生成 app.secret_key generate_secrets.py
1 2 3 4 import secretsprint (secrets.token_hex())
表单处理和验证的功能 1 2 name = StringField('Name' , validators=[DataRequired()]) email = EmailField('Email' , validators=[DataRequired(), Email()])
要求name和email非空,且email要符合格式
验证name和email 不输入name
不输入email
输入错误的email
输入name和正确格式的email
1 Exception: Install 'email_validator' for email validation support.
报错比较明显是还缺少emial_validator模块,通过命令行进行安装
1 pip3 install email_validator
继续请求,报错消失,但界面没有出现下面的效果
1 return f'Name: {name} , Email: {email} '
一开始以为是html中的name和email是小写,导致提交时找不到元素,然而还是不对。
IDE里的注释# Call validate only if the form is submitted. This is a shortcut for form.is_submitted() and form.validate().
所以加了打印看时哪个函数报错,结果是form.validate()
校验过程有问题,搜索相关资料,看怎么排查这个问题
请求方法错误 – POST请求,不是这个问题
表单数据错误 – 加上print(form.errors)
打印具体具体的错误 => {‘csrf_token’: [‘The CSRF tokens do not match.’]} …
是csrf_token未匹配的原因,对比了其它几种写法,未发现有什么特殊操作,其中提到清理浏览器缓存的操作,我一直都是使用Trae IDE自带的浏览器,抱着试一试的心态。用Chrome测试了下,是正常的!
我又问了Trae里的AI,看能不能告诉我怎么清理自带的浏览器,然后它的回答,始终讲不到点上。
在Trae起的web服务和主机起的web服务,应该是有差别的。都用了5000端口,所以不能同时起,两者不能相互访问。每次验证都要在关闭web再启动,为了后面遇到奇怪的问题可以用不同浏览器去对比验证。
Trae和主机传不同的port参数可以解决这个问题
1 2 3 4 5 import sysif __name__ == '__main__' : port = sys.argv[1 ] if len (sys.argv) > 1 else 5001 app.run(port=<port>,debug=True )
Chrome浏览器正常显示
表单验证 app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class MyForm2 (FlaskForm ): name = StringField('Name' , validators=[ DataRequired(), Length(min =1 , max =8 ) ]) email = EmailField('Email' , validators=[ DataRequired(), Email() ]) submit = SubmitField('Submit' ) @app.route('/form2' , methods=['GET' , 'POST' ] ) def form2 (): form = MyForm2() if form.validate_on_submit(): name = form.name.data email = form.email.data return redirect(url_for('form' )) return render_template('form.html' , form=form)
设置了Length,name最长只能输入8个
文件上传 Flask 还支持处理文件上传。上传的文件可以通过 request.files 访问。
templates/upload.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!DOCTYPE html > <html > <head > <title > Upload File</title > </head > <body > <form action ="/upload" method ="post" enctype ="multipart/form-data" > <label for ="file" > File:</label > <input type ="file" id ="file" name ="file" > <br > <input type ="submit" value ="Upload" > </form > </body > </html >
app.py
1 2 3 4 5 6 7 8 9 10 11 12 @app.route('/upload_file' , methods=['GET' ] ) def upload_form (): return render_template('upload.html' ) @app.route('/upload' , methods=['POST' ] ) def upload (): file = request.files.get('file' ) if file: filename = file.filename file.save(f'uploads/{filename} ' ) return f'File uploaded successfully: {filename} ' return 'No file uploaded'
访问/upload_file,选择文件并上传,上传成功后在app.py同级目录uploads下
CSRF 保护 Flask-WTF 自动为表单提供 CSRF 保护。你需要配置一个密钥来启用 CSRF 保护,并在模板中包含隐藏的 CSRF 令牌。
配置CSRF保护
app.py
1 app.secret_key = '6a31ad17a15b0d887049fcfd478aedeb8da2d40049f1413ca4add757379d4237'
在模板中添加 CSRF 令牌
1 2 3 4 <form method ="post" > {{ form.hidden_tag() }} </form >
Demo Flask
参考
Flask表单处理
Form Validation with WTForms
Flask WTF form.validate_on_submit()方法不起作用
flask总结05(在 Flask 项目中解决 CSRF 攻击)
Flask-WTF 表单令牌不匹配:The CSRF Tokens do not match