11

如何在滤锅中为以下形式的 JSON 定义模式?

{
    'data' : {
        'key_1' : [123, 567],
        'key_2' : ['abc','def'],
        'frank_underwood' : [666.66, 333.333],
        ... etc ...
    }
}

“数据”中的键可以是任何字符串,值是数组。

目前,我有以下内容,但它并没有真正对映射可以具有的值类型施加任何限制。

class Query(colander.MappingSchema):
    data = colander.SchemaNode(
        colander.Mapping(unknown='preserve'),
        missing={}
    )

描述这个的正确方式是什么?

4

3 回答 3

5

一种可能的解决方案是使用自定义验证器

这是一个自定义验证器的完整工作示例,它检查任意映射的所有值是否都是单数类型的数组。

import colander


def values_are_singularly_typed_arrays(node, mapping):
    for val in mapping.values():
        if not isinstance(val, list):
            raise colander.Invalid(node, "one or more value(s) is not a list")
        if not len(set(map(type, val))) == 1:
            raise colander.Invalid(node, "one or more value(s) is a list with mixed types")

class MySchema(colander.MappingSchema):
    data = colander.SchemaNode(
        colander.Mapping(unknown='preserve'),
        validator=values_are_singularly_typed_arrays
    )

def main():
    valid_data = {
        'data' : {
            'numbers' : [1,2,3],
            'reals' : [1.2,3.4,5.6],
        }
    }
    not_list = {
        'data' : {
            'numbers' : [1,2,3],
            'error_here' : 123
        }
    }
    mixed_type = {
        'data' : {
            'numbers' : [1,2,3],
            'error_here' : [123, 'for the watch']
        }
    }

    schema = MySchema()
    schema.deserialize(valid_data)

    try:
        schema.deserialize(not_list)
    except colander.Invalid as e:
        print(e.asdict())

    try:
        schema.deserialize(mixed_type)
    except colander.Invalid as e:
        print(e.asdict())

if __name__ == '__main__':
    main()
于 2015-01-08T05:34:23.400 回答
2

我不知道滤锅,但你可以使用 Spyne。

class Data(ComplexModel):
    key_1 = Array(Integer)
    key_2 = Array(Unicode)
    frank_underwood = Array(Double)

class Wrapper(ComplexModel):
    data = Data

完整的工作示例:https ://gist.github.com/plq/3081280856ed1c0515de

Spyne 的模型文档:http ://spyne.io/docs/2.10/manual/03_types.html


然而,事实证明这不是你需要的。如果您想要一个更松散指定的字典,那么您需要使用自定义类型:

class DictOfUniformArray(AnyDict):
    @staticmethod  # yes staticmethod
    def validate_native(cls, inst):
        for k, v in inst.items():
            if not isinstance(k, six.string_types):
                raise ValidationError(type(k), "Invalid key type %r")
            if not isinstance(v, list):
                raise ValidationError(type(v), "Invalid value type %r")
            # log_repr prevents too much data going in the logs.
            if not len(set(map(type, v))) == 1:
                raise ValidationError(log_repr(v),
                                      "List %s is not uniform")
        return True

class Wrapper(ComplexModel):
    data = DictOfUniformArray

完整的工作示例:https ://github.com/arskom/spyne/blob/spyne-2.12.5-beta/examples/custom_type.py

于 2015-07-18T21:41:21.780 回答
0

这是我找到的另一种方式。

from colander import SchemaType, Invalid
import json

class JsonType(SchemaType):
   ...
   def deserialize(self, node, cstruct):
    if not cstruct: return null
    try:
        result = json.loads(cstruct, encoding=self.encoding)
    except Exception as e:
        raise Invalid(node,"Not json ...")
    return result

如何在滤锅中创建“类型不可知”的 SchemaNode

于 2015-07-23T16:49:36.630 回答