美文网首页
wtForms 使用简介

wtForms 使用简介

作者: 番茄树叶 | 来源:发表于2017-06-19 23:04 被阅读1425次

    近期在用aiohttp替换tornado重构一部分api,其中一些接口需要验证比较多的请求参数,之前同事开发时挺赶的,直接在函数里一个个地验证参数,光验证参数得写一百五六十行代码。我重构时,想到用表单验证来解决这个问题,让代码不至于那么臃肿。


    官方文档

    http://wtforms.readthedocs.io/en/latest/


    示例程序

    示例程序web部分使用的是aiohttp,当然换成其他的像flask、tornado都行的。

    import json
    import traceback
    from multidict import MultiDict
    from aiohttp import web
    from wtforms import Form, StringField, validators, ValidationError
    
    class ActionForm(Form):
        action = StringField('action', [validators.Required()])
    
    async def task_handler(request):
        try:
            post_data = await request.text()
            post_data = json.loads(post_data)
            _form = ActionForm(MultiDict(post_data))
            if _form.validate():
                print('>>>> {} validate success'.format(post_data))
            else:
                print('<<<< {}'.format(_form.errors))
                return web.json_response({'message': 'form validate failed'}, status=400)
            return web.json_response({'message': 'task_handler'})
        except:
            traceback.print_exc()
            return web.json_response({'message': 'exception'})
    
    app = web.Application()
    app.router.add_post('/task', task_handler)
    
    web.run_app(app, host='127.0.0.1', port=8080)
    
    

    使用curl测试

    curl -l -H "Content-type: application/json" -X POST -d '{"action": "START"}' 127.0.0.1:8080/task
    >>> {"message": "task_handler"}
    

    说明

    • 定义了ActionForm,验证一个类型为String的字段action, validators.Required()表示该字段必须要有,若无则无法通过验证,validators.optional()表示该参数可选
    • 若post_data中有其他参数未在ActionForm定义的话,不会影响form的验证,直接忽略
    • 除了StringField外,还有其他如:BooleanField、DateField、IntegerField、PasswordField、FieldList、FormField等等,可以查看官方文档
    • FieldList是一个列表字段,可以指定list中field的类型
    • FormField类似一个字典字段,可以嵌套定义
    • 初始化Form后,调用validate()进行验证,若通过验证则返回True,否则返回False,失败的情况加Form的errors返回所有所有验证失败的字段及失败信息

    自定义验证函数 Custom validators

    在使用过程中,会有需求对字段进行更细化的验证,比如:希望action字段的字符串值在['START', 'CANCEL']范围内,此时就需要编写自定义的验证函数,对字段进行追加验证。

    增加一个validator,用于验证action字段在['START', 'CANCEL']范围内,若不在则抛出ValidationError异常:

    def my_action_check(form, field):
        if field.data not in ['START', 'CANCEL']:
            raise ValidationError('action must in [START, CANCEL]')
    

    ActionFormaction字段的validator列表中加入my_action_check,wtForms会按照先后顺序调用所有的validator对字段进行验证(链式调用,某个环节失败则不继续验证)

    class ActionForm(Form):
        action = StringField('action', [validators.Required(), my_action_check])
    
    • 此时调用接口时若传入action参数不为STARTCANCEL,则表单无法通过验证。
    • 验证函数的form字段即为当前的form对象,可用来获取其他字段的值进行联合验证
    • 验证函数的field字段即为当前的字段对象,通过field.data来获取值
    In-line Validators (内联?。。不知道怎么翻译)

    以上的方式使得验证函数具备一定的通用性,这里还有另一种方式用于验证字段,在Form类中定义validate_fieldname格式的函数,则Form会自动调用来验证对应的字段,函数同样接收两个参数:form, field

    class ActionForm(Form):
        action = StringField('action', [validators.Required()])
            
        def validate_action(form, field):
            if field.data not in ['START', 'CANCEL']:
                raise ValidationError('action must in [START, CANCEL]') 
    

    以上两种验证方式效果时一样的


    自定义字段 Custom Fields

    有的场景下,会post复杂的json数据,wtForms自带的字段会感觉不太够用,此时可以自己定义一个字段,能灵活验证数据。如嫌FieldList或者FormField用起来麻烦,可以自己定义一个ListField、DictField来验证列表和字典字段。

    自定义ListField,验证数组

    class ListField(Field):
    
        def process_formdata(self, valuelist):
            try:
                if valuelist[0] and isinstance(valuelist[0], list):
                    self.data = valuelist[0]
                else:
                    raise ValidationError('list validate error')
            except:
                raise ValidationError('list validate error, exception')
    

    使用curl测试

    curl -l -H "Content-type: application/json" -X POST -d '{"action": "START", "users": ["Tracy", "Kobe", "KD"]}' 127.0.0.1:8080/task
    
    >>> test python3 aiotest.py
    ======== Running on http://127.0.0.1:8080 ========
    (Press CTRL+C to quit)
    >>>> {'action': 'START', 'users': ['Tracy', 'Kobe', 'KD']} validate success
    

    users字段不传数组或数组为空则form无法通过验证

    • 自定义ListField时,需重写process_formdata方法处理初始化时传入的值,值通过valuelist[0]获取,若验证通过则将值赋给self.data,那么这个字段就有值了,后续的validators就可以对此值进行验证
    • validators.Required()实际做的事情就是判断字段的self.data是否为True

    小结

    wtForms还有一些其他用法在此就不再介绍了,翻阅文档吧。本文代码均使用python3.5运行。若有问题,欢迎交流。

    相关文章

      网友评论

          本文标题:wtForms 使用简介

          本文链接:https://www.haomeiwen.com/subject/xzynqxtx.html