2

我正在使用Cerberus验证作为 JSON 发布到基于 Flask 的 ReST-API 的数据。我想要两个字段中的至少一个freight_idtender_id在场。

这些映射将被视为有效:

{"freight_id": 1, "price" : 12000}

{"tender_id": 1, "price": 12000}

{"freight_id": 1, "tender_id" : 2, "price": 12000}

虽然这个不会:

{"price": 12000}

如何使用 Cerberus 为此类验证制定模式?

我几乎阅读了所有文档,但没有找到任何答案。-ruleexcludes不符合我的需要。

4

2 回答 2

4

@gcw 的解决方案可以更短:

from cerberus import Validator, rules_set_registry

required_integer = {'type': 'integer', 'required': True}

schemas = (
    {'freight_id': required_integer, 'price': required_integer},
    {'tender_id': required_integer, 'price': required_integer},
    {'freight_id': required_integer, 'tender_id': required_integer,
     'price': required_integer},
)

由于这三种模式无论如何都是互斥的,因此无需使用one_of规则,只需测试一个是否匹配:

validator = Validator()
valid = any(validator(document, schema) for schema in schemas)
于 2017-09-28T14:33:30.823 回答
4

使用 cerberus 1.0,您可以按照本文档示例oneof中的粘合形式实现此使用规则。有了这个,您可以针对必须验证的不同模式进行验证:

缺点是您可能需要在 dict 上增加一个级别,如下price所示:

第一种方案,运费和价格:

>>> schema_1 = {'freight_id': {'type': 'integer', 'required': True},
...             'price': {'type': 'integer', 'required': True}}

第二种模式,投标和价格:

>>> schema_2 = {'tender_id': {'type': 'integer', 'required': True},
...             'price': {'type': 'integer', 'required': True}}

第三种方案,运费、标书和价格:

>>> schema_3 = {'tender_id': {'type': 'integer', 'required': True},
...             'freight_id': {'type': 'integer', 'required': True},
...             'price': {'type': 'integer', 'required': True}}

把这些放在一起:

>>> from cerberus import Validator
>>>
>>> price_validator = Validator(
...     {'price': {'type': 'dict', 
...                'oneof_schema': [schema_1, schema_2, schema_3]}})

结果:

>>> price_validator.validate({"price": {"freight_id": 1, "price" : 12000}}) 
True
>>> price_validator.validate({"price": {"tender_id": 2, "price" : 12000}})
True
>>> price_validator.validate(
...     {"price": {"freight_id": 1, "tender_id": 2, "price": 1200}}) 
True

>>> price_validator.validate({"price": {"freight_id": 1, "tender_id": 2}}) 
False 
>>> price_validator.validate({"price": {"price" : 12000}})
False
于 2017-03-01T18:14:25.950 回答