Python Cerberus-仅当满足依赖关系时才需要字段

Python Cerberus-仅当满足依赖关系时才需要字段,python,cerberus,Python,Cerberus,考虑以下模式 schema = { "value_type":{ "type": "string", "required": True }, "units": { "type": "string", "dependencies": {"value_type": ["float", "integer"]}, "required": True } } 当value\u type字段的值为floa

考虑以下模式

schema = {
    "value_type":{
        "type": "string", "required": True
    }, 
    "units": {
        "type": "string", 
         "dependencies": {"value_type": ["float", "integer"]},
         "required": True
    }
}
value\u type
字段的值为
float
integer
时,我只希望
units
字段为必填项

以下是我的目标行为

v = Validator(schema)
v.validate({"value_type": "float", "units": "mm"})  # 1. 
True
v.validate({"value_type": "boolean", "units": "mm"})  # 2.
False
v.validate({"value_type": "float"})  # 3.
False
v.validate({"value_type": "boolean"})  # 4.
True
上述模式仅返回前3种情况的预期结果

如果我将
单位的定义更改为
(通过省略
“必需”:True

然后验证

v.validate({"value_type": "float"})  # 3.
True
返回
True
,这不是我想要的

我查看了中的
规则之一,但找不到将其仅应用于
required
属性的方法

仅当满足依赖项时,我希望required的值为
True


我应该如何修改我的模式来实现这一点?

由于您的变体跨越多个字段,因此
规则的
*并不完全合适,尤其是因为这些字段似乎是文档中的顶级字段

我通常会建议,仍然存在Python,并且并非所有内容都必须用模式表示,因此您可以简单地定义两个有效模式,并针对这些模式进行测试:

schema1 = {...}
schema2 = {...}

if not any(validator(document, schema=x) for x in (schema1, schema2)):
    boom()
这也比最终得到的任何模式都更容易理解

或者,您可以使用
检查规则。该示例显示了提交错误的两种不同方式,其中,当错误仅呈现给人时,后一种方式是可预制的,因为它们允许针对不同情况的自定义消息,但缺少有关错误的结构信息:

class MyValidator(Validator):
    def _check_with_units_required(self, field, value):
        if value in ("float", "integer"):
            if "units" not in self.document:
                self._error("units", errors.REQUIRED_FIELD, "check_with")
        else:
            if "units" in self.document:
                self._error(
                    "units", "The 'units' field must not be provided for value "
                             "types other than float or integer."
                )

schema = {
    "value_type": {
        "check_with": "units_required",
        "required": True,
        "type": "string"
    },
    "units": {
        "type": "string",
    }
}

validator = MyValidator(schema)

assert validator({"value_type": "float", "units": "mm"})
assert not validator({"value_type": "boolean", "units": "mm"})
assert not validator({"value_type": "float"})
assert validator({"value_type": "boolean"})

您使用的是哪个版本?我无法用当前的
master
分支头复制第四个示例的行为。我得到这个错误:
{'units':['required field']}
@funky future,版本是1.2。道歉,如果它是混乱的;该示例显示了我想要实现的行为。在运行这个时,我也会遇到同样的错误。那么,“上面的模式仅在前3种情况下返回预期结果”是什么意思?@funky future,我的意思是,按照
Schema
的定义方式,我在前3种情况下得到了我想要的结果(案例1:T,案例2:F,案例3:F),但在第4种情况下没有(在案例4中,我希望得到True,但我得到的是关于所需字段的错误)能够表达关系,而无需编写“代码”在我的例子中,这是一种要求,但我明白你关于可读性和可理解性的观点。@helplessKirk当然,在很多情况下,所有内容都应该集中在一个模式中。在这种情况下,我建议使用
check\u with
规则,这样人们也可以使用非通用的错误消息,这些错误消息通常更复杂d向用户指出问题所在。感谢您对
check_with
规则的建议。您认为您可以添加一个示例,这样我也可以接受答案吗?@helplessKirk我添加了这个示例。@funky future,谢谢!您救了我一天!效果非常好。我们搜索Cerberus docs大约3个小时,以找到问题的答案相同的用例。
class MyValidator(Validator):
    def _check_with_units_required(self, field, value):
        if value in ("float", "integer"):
            if "units" not in self.document:
                self._error("units", errors.REQUIRED_FIELD, "check_with")
        else:
            if "units" in self.document:
                self._error(
                    "units", "The 'units' field must not be provided for value "
                             "types other than float or integer."
                )

schema = {
    "value_type": {
        "check_with": "units_required",
        "required": True,
        "type": "string"
    },
    "units": {
        "type": "string",
    }
}

validator = MyValidator(schema)

assert validator({"value_type": "float", "units": "mm"})
assert not validator({"value_type": "boolean", "units": "mm"})
assert not validator({"value_type": "float"})
assert validator({"value_type": "boolean"})