美文网首页python小项目练习
Flask请求参数类型判断

Flask请求参数类型判断

作者: 野生大灰狼 | 来源:发表于2017-08-12 18:08 被阅读114次

    一个最小的Flask应用

    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify, request
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    def fight():
        name = request.args.get('name')
        return jsonify(dict(data=name))
    
    # encoding:utf-8
    # runserver.py
    from app import app
    __author__ = '零四二零'
    
    if __name__ == '__main__':
        app.run(host="0.0.0.0", port=5000, threaded=True)
    

    请求http://0.0.0.0:5000?name=123

    image.png

    一个简单的想法是在函数内部判断name的属性,不符合就返回错误信息,实现起来很简单

    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify, request
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    def fight():
        name = request.args.get('name', '')
        if not name:
            return jsonify(dict(error='缺少参数'))
        try:
            name = int(name)
        except ValueError:
            return jsonify(dict(error='参数格式错误'))
        return jsonify(dict(data=name))
    

    请求http://0.0.0.0:5000

    image.png

    请求http://0.0.0.0:5000?name=fight

    image.png

    这种写法非常不美,把类型判断剥离开来,改成装饰器,统一调用

    # encoding:utf-8
    # validator.py
    from flask import request, jsonify
    __author__ = '零四二零'
    
    def validator_int(func):
        def _decorate():
            name = request.args.get('name', '')
            if not name:
                return jsonify(dict(error='缺少参数'))
            try:
                name = int(name)
            except ValueError:
                return jsonify(dict(error='参数格式错误'))
            return func()
        return _decorate
    
    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify, request
    from validator import validator_int
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET'])
    @validator_int
    def fight():
        name = request.args.get('name', '')
        return jsonify(dict(data=name))
    

    😎大功告成,继续优化,使用Flask的异常处理,并支持默认参数

    # encoding:utf-8
    # validator.py
    from flask import request
    __author__ = '零四二零'
    
    def validator_int(func):
        def _decorate():
            arg = request.args.get('name', '666')
            if not arg:
                raise Exception('缺少参数')
            try:
                name = int(arg)
            except ValueError:
                raise Exception('参数格式错误')
            return func(arg)
        return _decorate
    
    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify
    from validator import validator_int
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.errorhandler(Exception)
    def error(e):
        return jsonify(dict(error=e.message))
    
    @app.route('/', methods=['GET'])
    @validator_int
    def fight(name):
        return jsonify(dict(data=name))
    

    请求http://0.0.0.0:5000

    image.png
    默认是写在validator_int里并不是最好的选择,移到fight中,需要用到inspect库来获取fight的参数信息
    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify
    from validator import validator_int
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.errorhandler(Exception)
    def error(e):
        return jsonify(dict(error=e.message))
    
    
    @app.route('/', methods=['GET'])
    @validator_int
    def fight(name='666'):
        return jsonify(dict(data=name))
    
    # encoding:utf-8
    # validator.py
    import inspect
    from flask import request
    __author__ = '零四二零'
    
    def validator_int(func):
        def _decorate():
            arg = request.args.get('name', '')
            if not arg:
                func_args = inspect.getargspec(func)
                defaults = func_args.defaults[0]
                arg = func_args.args[0]
            try:
                name = int(defaults)
            except ValueError:
                raise Exception('参数格式错误')
            return func(**{arg: defaults})
        return _decorate
    

    支持多参数操作,有默认值的加上默认值

    # encoding:utf-8
    # validator.py
    import inspect
    import json
    from flask import request
    __author__ = '零四二零'
    
    REQUEST_METHOD_MAP = {'GET': 'args', 'POST': 'form'}
    
    
    def _params_covert(val):
        val = val[0] if isinstance(val, list) else val
        try:
            val = json.loads(val)
        except (ValueError, TypeError):
            pass
        return val
    
    
    def _get_request_params():
        params = request.json or {}
        for k, v in dict(getattr(request, REQUEST_METHOD_MAP.get(request.method))).iteritems():
            params[k] = _params_covert(v)
        return params
    
    
    def _param_int_validator(val):
        try:
            _ = int(val)
        except (ValueError, TypeError):
            return False
        return True
    
    def validator_int(func):
        def _decorate():
            params = _get_request_params()
            func_args = inspect.getargspec(func)
            default_val, args, kwargs, args_len = func_args.defaults or [], [], {}, len(func_args.args)
            for index, func_arg in enumerate(func_args.args):
                default_index = index + len(default_val) - args_len
                if default_index < 0:
                    if func_arg not in params:
                        raise Exception('缺少参数:{0}'.format(func_arg))
                    else:
                        if not _param_int_validator(params[func_arg]):
                            raise Exception('参数格式错误')
                        args.append(params[func_arg])
                else:
                    kwargs[func_arg] = params[func_arg] if func_arg in params else default_val[default_index]
            for k, v in kwargs.iteritems():
                if not _param_int_validator(v):
                    raise Exception('参数:{0} 格式错误'.format(k))
            return func(*args, **kwargs)
        return _decorate
    
    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify
    from validator import validator_int
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    @app.errorhandler(Exception)
    def error(e):
        return jsonify(dict(error=e.message))
    
    @app.route('/', methods=['GET'])
    @validator_int
    def fight(sex, name='666', age='18'):
        return jsonify(dict(name=name, age=age, sex=sex))
    

    请求http://0.0.0.0:5000?sex=1

    image.png

    再接再厉,支持指定参数类型判断,validator_int需要接受一个dict参数,里面是各个参数的字段类型

    # encoding:utf-8
    # validator.py
    import inspect
    import json
    from flask import request
    __author__ = '零四二零'
    
    REQUEST_METHOD_MAP = {'GET': 'args', 'POST': 'form'}
    
    
    def _params_covert(val):
        val = val[0] if isinstance(val, list) else val
        try:
            val = json.loads(val)
        except (ValueError, TypeError):
            pass
        return val
    
    
    def int_field(value):
        try:
            _ = int(value)
        except (ValueError, TypeError):
            return False
        return True
    
    
    def str_field(value):
        try:
            import re
            if not re.compile('.*').match(value):
                return False
        except (ValueError, TypeError):
            return False
        return True
    
    
    def list_field(value):
        try:
            if not isinstance(value, list):
                value = json.loads(value)
                _ = [x.strip() for x in value.split(',')]
        except (ValueError, TypeError):
            return False
        return True
    
    
    def dict_field(value):
        try:
            if not isinstance(value, dict):
                _ = json.loads(value)
        except (ValueError, TypeError):
            return False
        return True
    
    
    def bool_field(value):
        try:
            bool(value)
        except (ValueError, TypeError):
            return False
        return True
    
    
    def float_field(value):
        try:
            _ = float(value)
        except (ValueError, TypeError):
            return False
        return True
    
    
    def _get_request_params():
        params = request.json or {}
        for k, v in dict(getattr(request, REQUEST_METHOD_MAP.get(request.method))).iteritems():
            params[k] = _params_covert(v)
        return params
    
    
    def validator_int(param_fields):
        def _decorate(func):
            def __decorate():
                params = _get_request_params()
                func_args = inspect.getargspec(func)
                default_val, args, kwargs, args_len = func_args.defaults or [], [], {}, len(func_args.args)
                for index, func_arg in enumerate(func_args.args):
                    if func_arg not in param_fields:
                        raise Exception('参数:{0}, 未指明类型'.format(func_arg))
                    default_index = index + len(default_val) - args_len
                    param_func = param_fields[func_arg]
                    if default_index < 0:
                        if func_arg not in params:
                            raise Exception('缺少参数:{0}'.format(func_arg))
                        else:
                            if not param_func(params[func_arg]):
                                raise Exception('参数:{0}格式错误, 需要类型:{1}'.format(func_arg, param_func.__name__))
                            args.append(params[func_arg])
                    else:
                        kwargs[func_arg] = params[func_arg] if func_arg in params else default_val[default_index]
                for k, v in kwargs.iteritems():
                    if not param_fields[k](v):
                        raise Exception('参数:{0} 格式错误, 需要类型:{1}'.format(k, param_fields[k].__name__))
                return func(*args, **kwargs)
            return __decorate
        return _decorate
    
    # encoding:utf-8
    # app.py
    from flask import Flask, jsonify
    from validator import validator_int, int_field, dict_field, list_field
    __author__ = '零四二零'
    
    app = Flask(__name__)
    
    
    @app.errorhandler(Exception)
    def error(e):
        return jsonify(dict(error=e.message))
    
    
    @app.route('/', methods=['GET'])
    @validator_int(dict(name=dict_field, sex=list_field, age=int_field))
    def fight(sex, name, age=18):
        return jsonify(dict(name=name, age=age, sex=sex))
    

    请求http://0.0.0.0:5000?sex=[1,2,3]&name={"name":"fight"}

    image.png
    请求http://0.0.0.0:5000?sex=[1,2,3]&name=123 image.png

    「欢迎分享,优化」

    相关文章

      网友评论

        本文标题:Flask请求参数类型判断

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