Python全栈(七)Flask框架之11.WTForms及其应用和Cookie的简单使用

Florida ·
更新时间:2024-11-13
· 626 次阅读

文章目录一、WTForms表单验证1.表单验证的基本使用2.Flask-WTF常用的验证器EmailNumber必填正则表达式URL扩展-验证码的验证二、WTF渲染模板三、WTF文件上传1.文件上传的基本使用2.文件上传的表单验证3.访问上传资源四、Cookie的使用1.Cookie的基本概念2.Flask中使用Cookie
flask-wtf是一个简化了WTFForms操作的第三方库,WTForms表单的两个主要功能是验证用户提交数据的合法性渲染模板,还包括一些其他的功能,如CSRF保护、文件上传等。
安装flask-wtf使用命令pip install flask-wtf一、WTForms表单验证 1.表单验证的基本使用

不使用WTF进行表单验证测试:
创建程序主入口wtf_demo.py:

from flask import Flask, request, render_template app = Flask(__name__) @app.route('/') def index(): return '首页' @app.route('/register/', methods=['GET', 'POST']) def register(): if request.method == 'GET': return render_template('register.html') else: username = request.form.get('username') password = request.form.get('password') pwd_confirm = request.form.get('pwd_confirm') if len(username) 15: return '用户名长度不正确' if password != pwd_confirm: return '两次密码输入不一致' if len(username) 20: return '密码长度不正确' if __name__ == '__main__': app.run(debug=True)

模板目录templates下创建register.html如下:

注册 用户名:
密码:
确认密码:

显示:
flask form normal verification

显然,可以达到验证表单的效果,但是在register()视图函数中一般只是得到验证是否成功的结果即可,可以将验证单独抽离出来,使用flask-wtf进行专门验证,新建forms.py如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')])

修改wtf_demo.py如下:

from flask import Flask, request, render_template from forms import RegisterForm app = Flask(__name__) @app.route('/') def index(): return '首页' @app.route('/register/', methods=['GET', 'POST']) def register(): if request.method == 'GET': return render_template('register.html') else: form = RegisterForm(request.form) if form.validate(): return '验证成功' else: return '验证失败:\n' + str(form.errors) if __name__ == '__main__': app.run(debug=True)

RegisterForm初始化时传入request.form,并且根据form.validate()的值来判断用户提交的数据是否满足表单的验证。

显示:
flask form wtf verification
在forms.py中指定了需要上传的参数,并且指定了验证器,比如username的长度应该在3-15之间,password长度必须在6-20之间,并且应该和pwd_confirm相等才能通过验证。

2.Flask-WTF常用的验证器 Email

可以直接使用Email类进行右键地址的验证。
在forms.py中新增LoginForm如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo, Email class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): email = StringField(validators=[Email(message='邮箱格式不正确')])

主程序中增加视图函数:

from flask import Flask, request, render_template from forms import RegisterForm, LoginForm app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/register/', methods=['GET', 'POST']) def register(): if request.method == 'GET': return render_template('register.html') else: form = RegisterForm(request.form) if form.validate(): return '验证成功' else: return '验证失败:\n' + str(form.errors) @app.route('/login/', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') else: form = LoginForm(request.form) if form.validate(): return '验证成功' else: return '验证失败:\n' + str(form.errors) if __name__ == '__main__': app.run(debug=True)

新建login.html如下:

登录
邮箱:

运行主程序,显示:
flask wtf email

Number

可以通过NumberRange类对数的范围进行验证。
修改forms.py如下;

from wtforms import Form, StringField, IntegerField from wtforms.validators import Length, EqualTo, Email, NumberRange class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): age = IntegerField(validators=[NumberRange(1, 120, message='年龄范围有误!!!')])

修改login.html如下:

登录
年龄:

显示:
flask wtf number

必填

可以通过InputRequired类限制某些字段必填。
forms.py修改如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo, InputRequired class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): username = StringField(validators=[InputRequired(message='用户名必填')])

login.html修改如下:

登录
用户名:

显示:
flask wtf inputrequired

正则表达式

可以通过Regexp类自定义正则表达式进行验证。
forms.py修改如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo, Regexp class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): phone_number = StringField(validators=[Regexp(r'1[35789]\d{9}', message='手机号码不正确')])

login.py修改如下:

登录
手机号:

显示:
flask wtf regexp

URL

可以使用URL类验证某个字符串是否是标准的URL格式。
forms.py修改如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo, URL class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): info_page = StringField(validators=[URL(message='地址格式不正确')])

login.html修改如下:

登录
个人主页:

显示:
flask wtf url

扩展-验证码的验证

要验证验证码长度和有效性,长度用Length验证,有效性可以在表单类中自定义方法即可。

forms.py修改如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo, ValidationError class RegisterForm(Form): username = StringField(validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField(validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField(validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')]) class LoginForm(Form): captcha = StringField(validators=[Length(min=4, max=4, message='验证码不正确')]) def validate_captcha(self, field): '''自定义验证,方法名为固定格式,即validate_加要验证的变量名''' if field.data != '1234': raise ValidationError("验证码错误")

login.html修改如下:

登录
验证码:

显示:
flask wtf captcha

二、WTF渲染模板

wtforms可以渲染模板,省去一部分代码。
测试:
wtf_demo.py如下:

from flask import Flask, request, render_template from forms import RegisterForm app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/register/', methods=['GET', 'POST']) def register(): form = RegisterForm(request.form) if request.method == 'GET': return render_template('register.html', form=form) else: username = form.username.data password = form.password.data pwd_confirm = form.pwd_confirm.data if form.validate(): return '验证成功--User: ' + username + ' Password: ' + password else: return '验证失败:\n' + str(form.errors) if __name__ == '__main__': app.run(debug=True)

在渲染模板的时候传入了form表单参数,这样在模板中就可以使用表单form变量了。
forms.py如下:

from wtforms import Form, StringField from wtforms.validators import Length, EqualTo class RegisterForm(Form): username = StringField('用户名', validators=[Length(min=3, max=15, message='用户名长度不正确')]) password = StringField('密码', validators=[Length(min=6, max=20, message='密码长度不正确')]) pwd_confirm = StringField('密码确认', validators=[Length(min=6, max=20), EqualTo('password', message='两次密码不一致')])

每个变量都增加了一个位置参数,用于在html文件中做标签提示。
register.html如下:

注册
{{ form.username.label }} {{ form.username() }}
{{ form.password.label }} {{ form.password() }}
{{ form.pwd_confirm.label }} {{ form.pwd_confirm() }}

显示:
flask wtf render template

三、WTF文件上传 1.文件上传的基本使用

先创建项目目录flask_upload,创建主文件flask_app.py如下:

from flask import Flask, request,render_template from werkzeug.utils import secure_filename app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/upload/', methods=['GET', 'POST']) def upload(): if request.method == 'GET': return render_template('upload.html') else: desc = request.form.get('desc') image_file = request.files.get('image_file') file_name = secure_filename(image_file.filename) image_file.save('files/images/' + file_name) return '文件上传成功--' + desc if __name__ == '__main__': app.run(debug=True)

创建templates目录,下面创建upload.html如下:

文件上传 {# 文件上传,form表单必须要添加enctype属性 #}
头像
描述

在项目目录下创建files文件夹用于保存上传的文件,下面创建images子目录,运行主程序之后,显示:
flask wtf upload
显然,文件上传成功。
我们可以得到:
在模版中的form标签中,需要指定enctype='multipart/form-data'才能上传文件;
在后台如果想要获取上传的文件,应该使用request.files.get(file_name)来获取;
保存文件之前,先要使用werkzeug.utils类中的secure_filename()方法来对上传上来的文件名进行过滤,以确保安全性;
获取到上传上来的文件后,使用filename.save(路径)方法来保存文件。

可以看到,在上传的文件中,纯英文文件名保留不变,有中文的将中文去掉,这是由于werkzeug.utils模块中的secure_filename方法只支持ASCII编码的字符,这个问题是可以解决的,可参考https://blog.csdn.net/qq_36390239/article/details/98847888解决。

2.文件上传的表单验证

上面虽然上传文件成功,但是并未对文件进行验证,存在很大的风险。

进行文件验证测试:
新建forms.py如下:

from wtforms import Form, FileField, StringField from wtforms.validators import InputRequired from flask_wtf.file import FileAllowed, FileRequired class UploadForm(Form): image_file = FileField(validators=[FileRequired(message='文件必须上传'), FileAllowed(['jpg', 'png', 'gif'], message='上传文件格式有误')]) desc = StringField(validators=[InputRequired('必须填写描述')])

修改flask_app.py如下:

from flask import Flask, request,render_template from werkzeug.utils import secure_filename from werkzeug.datastructures import CombinedMultiDict from forms import UploadForm app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/upload/', methods=['GET', 'POST']) def upload(): if request.method == 'GET': return render_template('upload.html') else: form = UploadForm(CombinedMultiDict([request.form, request.files])) if form.validate(): desc = request.form.get('desc') # 等价于desc = form.desc.data image_file = request.files.get('image_file') # 等价于image_file = form.image_file.data file_name = secure_filename(image_file.filename) image_file.save('files/images/' + file_name) return '文件上传成功--' + desc else: return '文件上传失败--' + str(form.errors) if __name__ == '__main__': app.run(debug=True)

显示:
flask wtf upload validate
显然,已经实现了文件上传时的验证,其中:

desc = request.form.get('desc') image_file = request.files.get('image_file')

等价于

desc = form.desc.data image_file = form.image_file.data

可以得到:
定义表单的时候,对文件的字段需要使用FileField
验证器从flask_wtf.file中导入,FileRequired是用来验证文件上传是否为空,FileAllowed用来验证上传的文件的后缀名;
在视图文件中,使用werkzeug.datastructures类中的CombinedMultiDict()方法将request.form与request.files合并,再传给表单进行验证。

3.访问上传资源

想要读取上传的文件时,需要定义一个视图函数,来获取指定的文件。
在这个视图函数中,使用send_from_directory(文件的目录, 文件名)来获取。

flask_app.py如下:

from flask import Flask, request, render_template, send_from_directory from werkzeug.utils import secure_filename from werkzeug.datastructures import CombinedMultiDict from forms import UploadForm app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/upload/', methods=['GET', 'POST']) def upload(): if request.method == 'GET': return render_template('upload.html') else: form = UploadForm(CombinedMultiDict([request.form, request.files])) if form.validate(): desc = request.form.get('desc') # 等价于desc = form.desc.data image_file = request.files.get('image_file') # 等价于image_file = form.image_file.data file_name = secure_filename(image_file.filename) image_file.save('files/images/' + file_name) return '文件上传成功--' + desc else: return '文件上传失败--' + str(form.errors) @app.route('/images/') def get_image(filename): return send_from_directory('files/images/', filename) if __name__ == '__main__': app.run(debug=True)

显示:
flask wtf upload access resources
很明显,成功访问到了资源。

四、Cookie的使用 1.Cookie的基本概念

在网站中,http请求是无状态的,也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。
cookie的出现就是为了解决这个问题,类型为小型文本文件,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动将上次请求存储的cookie数据自动传送给服务器,服务器通过浏览器携带的数据来判断用户。
cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。

2.Flask中使用Cookie

在Flask中操作cookie,是通过Response对象来操作,可以在response返回之前,通过response.set_cookie()方法来设置,这个方法有以下几个参数:

key
cookie的键
value
cookie的键对应的值。 max_age
cookie的过期时间,如果不设置,则浏览器关闭后就会自动过期。 expires
过期时间,时间戳的形式(1970到现在的时间)。 domain
该cookie在哪个域名中有效,一般设置子域名,比如cms.example.com。 path
该cookie在哪个路径下有效,即当前主域名。

cookie简单测试:
flask_app.py如下:

from flask import Flask, Response app = Flask(__name__) app.config['TEMPLATE_AUTO_RELOAD'] = True @app.route('/') def index(): return '首页' @app.route('/cookietest/') def cookietest(): res = Response('Hello World!!') res.set_cookie('username', value='corley', max_age=3) return res if __name__ == '__main__': app.run(debug=True)

显示:

flask cookie simple use

cutercorley 原创文章 129获赞 1434访问量 35万+ 关注 私信 展开阅读全文
作者:cutercorley



python全栈 flask Python cookie

需要 登录 后方可回复, 如果你还没有账号请 注册新账号