Don't repeat yourselfpython
在使用Flask-WTF的時候,常會用下面這樣的代碼來驗證表單數據的合法性:git
from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
form = TestForm()
# 判斷是否合法
if not form.validate_on_submit():
return 'err', 400
# 主要邏輯
複製代碼
對於有不少提交接口的項目來講,須要在每一個路由下寫相同的的邏輯,形成了大量的代碼重複。在Flask-Login中,要把一個路由設置爲登陸後才能訪問,只須要在路由上加一個@login_required裝飾器,不須要額外的代碼。能不能像Flask-Login同樣,用裝飾器來封裝對錶單的驗證邏輯呢?github
因爲不一樣路由使用的表單類不同,因此須要爲裝飾器傳入一個表單類參數,而且在路由函數中須要用到表單中的值,因此還須要將驗證經過的表單傳給路由函數。json
上代碼:flask
def validate_form(self, form_cls):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
if not form.validate_on_submit():
return 'error', 400
return fn(form, *args, **kwargs)
return wrapper
return decorator
複製代碼
使用方式以下:app
@validate_form(TestForm) # 須要傳入要驗證的表單類
@app.route('/', methods=['GET', 'POST'])
def index(form):
# 執行到這裏說明表單驗證經過
複製代碼
通過在項目中的應用,發現裝飾器仍是有一些缺陷:函數
要自定義處理非法表單的邏輯,須要增長一個能夠傳入自定義邏輯的接口。表單非法時接口的返回每每是一致的,因此咱們爲全部應用裝飾器的路由傳入一個統一的處理邏輯。將裝飾器封裝在一個類中,在類中添加一個配置處理邏輯的方法。post
from functools import wraps
from flask import request
class FormValidator(object):
def __init__(self, error_handler=None):
self._error_handler = error_handler
def validate_form(self, form_cls):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
if not form.validate_on_submit() and self._error_handler:
return self._error_handler(form.errors)
return fn(form, *args, **kwargs)
return wrapper
return decorator
def error_handler(self, fn):
self._error_handler = fn
return fn
複製代碼
error_handler也是一個裝飾器,被它修飾的方法就是處理非法表單的方法。ui
@form_validator.error_handler
def error_handler(errors):
return jsonify({'errors': errors}), 400
複製代碼
接下來支持get方法,在flask中,咱們能夠經過request.args來獲取到get方法提交的參數。思路是用獲取到的參數生成一個表單類的實例,而後就能夠經過調用表單類的validate()方法來判斷是否合法了。修改validate_form裝飾器:spa
def validate_form(self, form_cls):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
if request.method == 'GET':
form = form_cls(formdata=request.args)
elif request.method in ('POST', 'PUT'):
form = form_cls()
else:
return fn(*args, **kwargs)
if not form.validate() and self._error_handler:
return self._error_handler(form.errors)
return fn(form, *args, **kwargs)
return wrapper
return decorator
複製代碼
大功告成!使用上面的裝飾器,就能夠免除在路由函數中重複寫表單驗證邏輯,而且同時支持put、post和get方法提交的表單。
#開箱即用
筆者已經把上面的代碼封裝成了一個庫發佈到了PyPI,想直接用的朋友可使用pip install flask-wtf-decorators
安裝,項目源碼也已經發布到Github。