用装饰器封装Flask-WTF表单验证逻辑
Posted Python私房菜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用装饰器封装Flask-WTF表单验证逻辑相关的知识,希望对你有一定的参考价值。
“ Don't repeat yourself ”
在使用Flask-WTF的时候,常会用下面这样的代码来验证表单数据的合法性:
1from flask import Flask
2
3app = Flask(__name__)
4
5@app.route('/', methods=['GET', 'POST'])
6def index():
7 form = TestForm()
8 # 判断是否合法
9 if not form.validate_on_submit():
10 return 'err', 400
11 # 主要逻辑
对于有很多提交接口的项目来说,需要在每个路由下写相同的的逻辑,造成了大量的代码重复。在Flask-Login中,要把一个路由设置为登录后才能访问,只需要在路由上加一个@login_required装饰器,不需要额外的代码。能不能像Flask-Login一样,用装饰器来封装对表单的验证逻辑呢?
01
—
实现表单验证装饰器
由于不同路由使用的表单类不一样,所以需要为装饰器传入一个表单类参数,并且在路由函数中需要用到表单中的值,所以还需要将验证通过的表单传给路由函数。
上代码:
1def validate_form(self, form_cls):
2 def decorator(fn):
3 @wraps(fn)
4 def wrapper(*args, **kwargs):
5 if not form.validate_on_submit():
6 return 'error', 400
7 return fn(form, *args, **kwargs)
8 return wrapper
9 return decorator
使用方式如下:
1@validate_form(TestForm) # 需要传入要验证的表单类
2@app.route('/', methods=['GET', 'POST'])
3def index(form):
4 # 执行到这里说明表单验证通过
经过在项目中的应用,发现装饰器还是有一些缺陷:
- 无法自定义处理非法表单的逻辑
- 不支持get方式提交的表单(查看validate_on_submit()源码可知其只支持对post和put方式提交的表单进行验证)
02
—
丰富一下
要自定义处理非法表单的逻辑,需要增加一个可以传入自定义逻辑的接口。表单非法时接口的返回往往是一致的,所以我们为所有应用装饰器的路由传入一个统一的处理逻辑。将装饰器封装在一个类中,在类中添加一个配置处理逻辑的方法。
1from functools import wraps
2
3from flask import request
4
5
6class FormValidator(object):
7
8 def __init__(self, error_handler=None):
9 self._error_handler = error_handler
10
11 def validate_form(self, form_cls):
12 def decorator(fn):
13 @wraps(fn)
14 def wrapper(*args, **kwargs):
15 if not form.validate_on_submit() and self._error_handler:
16 return self._error_handler(form.errors)
17 return fn(form, *args, **kwargs)
18 return wrapper
19 return decorator
20
21 def error_handler(self, fn):
22 self._error_handler = fn
23 return fn
error_handler也是一个装饰器,被它修饰的方法就是处理非法表单的方法。
1@form_validator.error_handler
2def error_handler(errors):
3 return jsonify({'errors': errors}), 400
接下来支持get方法,在flask中,我们可以通过request.args来获取到get方法提交的参数。思路是用获取到的参数生成一个表单类的实例,然后就可以通过调用表单类的validate()方法来判断是否合法了。修改validate_form装饰器:
1def validate_form(self, form_cls):
2 def decorator(fn):
3 @wraps(fn)
4 def wrapper(*args, **kwargs):
5 if request.method == 'GET':
6 form = form_cls(formdata=request.args)
7 elif request.method in ('POST', 'PUT'):
8 form = form_cls()
9 else:
10 return fn(*args, **kwargs)
11 if not form.validate() and self._error_handler:
12 return self._error_handler(form.errors)
13 return fn(form, *args, **kwargs)
14 return wrapper
15 return decorator
大功告成!使用上面的装饰器,就可以免除在路由函数中重复写表单验证逻辑,并且同时支持put、post和get方法提交的表单。
03
—
开箱即用
笔者已经把上面的代码封装成了一个库发布到了PyPI,想直接用的朋友可以使用`pip install flask-wtf-decorators`安装,项目源码也已经发布到Github。
在Github或PyPI搜索【Flask-WTF-Decorators】
快来关注Python私房菜哟
以上是关于用装饰器封装Flask-WTF表单验证逻辑的主要内容,如果未能解决你的问题,请参考以下文章
Zend Framework 表单、装饰器和验证:我应该回到纯 HTML 吗?