用裝飾器封裝Flask-WTF表單驗證邏輯

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):
    # 執行到這裏說明表單驗證經過
複製代碼

通過在項目中的應用,發現裝飾器仍是有一些缺陷:函數

  • 沒法自定義處理非法表單的邏輯
  • 不支持get方式提交的表單(查看validate_on_submit()源碼可知其只支持對post和put方式提交的表單進行驗證)

豐富一下

要自定義處理非法表單的邏輯,須要增長一個能夠傳入自定義邏輯的接口。表單非法時接口的返回每每是一致的,因此咱們爲全部應用裝飾器的路由傳入一個統一的處理邏輯。將裝飾器封裝在一個類中,在類中添加一個配置處理邏輯的方法。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。

查看PyPI

查看Github

相關文章
相關標籤/搜索