使用flask-restful RequestParser进行嵌套验证

Dan*_*aab 28 python rest flask flask-restful

使用burn-restful微框架,我在构建一个RequestParser验证嵌套资源的问题时遇到了麻烦.假设表单的预期JSON资源格式:

{
    'a_list': [
        {
            'obj1': 1,
            'obj2': 2,
            'obj3': 3
        },
        {
            'obj1': 1,
            'obj2': 2,
            'obj3': 3
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

每个项目a_list对应一个对象:

class MyObject(object):
    def __init__(self, obj1, obj2, obj3)
        self.obj1 = obj1
        self.obj2 = obj2
        self.obj3 = obj3
Run Code Online (Sandbox Code Playgroud)

...然后,可以使用以下形式创建RequestParser:

from flask.ext.restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('a_list', type=MyObject, action='append')
Run Code Online (Sandbox Code Playgroud)

...但是你如何验证MyObject里面每个字典的嵌套a_list?或者,这是错误的方法吗?

对应的API对应于将每个处理MyObject为对象文字,并且可能有一个或多个传递给服务; 因此,扁平化资源格式不适用于这种情况.

bar*_*ite 23

通过RequestParser为嵌套对象创建实例,我获得了成功.首先解析根对象,然后使用结果输入嵌套对象的解析器.

诀窍是location该参数的add_argument方法和req对参数的parse_args方法.他们让你操纵RequestParser看起来的东西.

这是一个例子:

root_parser = reqparse.RequestParser()
root_parser.add_argument('id', type=int)
root_parser.add_argument('name', type=str)
root_parser.add_argument('nested_one', type=dict)
root_parser.add_argument('nested_two', type=dict)
root_args = root_parser.parse_args()

nested_one_parser = reqparse.RequestParser()
nested_one_parser.add_argument('id', type=int, location=('nested_one',))
nested_one_args = nested_one_parser.parse_args(req=root_args)

nested_two_parser = reqparse.RequestParser()
nested_two_parser.add_argument('id', type=int, location=('nested_two',))
nested_two_args = nested_two_parser.parse_args(req=root_args)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢@barqshasbite - 您能举例说明您的数据结构是如何形成的吗? (3认同)

kar*_*daj 7

我建议使用像cerberus这样的数据验证工具.首先定义对象的验证模式(段中介绍了嵌套对象模式),然后使用验证器根据模式验证资源.验证失败时,您还会收到详细的错误消息.

在以下示例中,我想验证位置列表:

from cerberus import Validator
import json


def location_validator(value):
    LOCATION_SCHEMA = {
        'lat': {'required': True, 'type': 'float'},
        'lng': {'required': True, 'type': 'float'}
    }
    v = Validator(LOCATION_SCHEMA)
    if v.validate(value):
        return value
    else:
        raise ValueError(json.dumps(v.errors))
Run Code Online (Sandbox Code Playgroud)

参数定义如下:

parser.add_argument('location', type=location_validator, action='append')
Run Code Online (Sandbox Code Playgroud)


bbe*_*e10 5

由于type这里的参数只是一个可调用的,它可以返回一个解析的值或者在无效类型上引发ValueError,我建议为此创建自己的类型验证器.验证器可能看起来像:

from flask.ext.restful import reqparse
def myobj(value):
    try:
        x = MyObj(**value)
    except TypeError:
        # Raise a ValueError, and maybe give it a good error string
        raise ValueError("Invalid object")
    except:
        # Just in case you get more errors
        raise ValueError 

    return x


#and now inside your views...
parser = reqparse.RequestParser()
parser.add_argument('a_list', type=myobj, action='append')
Run Code Online (Sandbox Code Playgroud)