如何在Cerberus中为递归数据结构(如树)建模Schema并验证?
Cerberus v1.3.5 递归树形结构验证的正确Schema建模方式
需求
使用Python Cerberus(v1.3.5)验证递归树形数据结构:节点要么是包含value整数字段的叶子节点,要么是包含任意深度子节点的分支节点。
尝试过程
尝试#1
尝试通过schema_registry定义递归结构:
from cerberus import Validator, schema_registry schema_registry.add("leaf", {"value": {"type": "integer", "required": True}}) schema_registry.add("tree", {"type": "dict", "anyof_schema": ["leaf", "tree"]}) v = Validator(schema = {"root": {"type": "dict", "schema": "tree"}})
错误信息:
cerberus.schema.SchemaError: {'root': [{ 'schema': [ 'no definitions validate', { 'anyof definition 0': [{ 'anyof_schema': ['must be of dict type'], 'type': ['null value not allowed'], }], 'anyof definition 1': [ 'Rules set definition tree not found.' ], }, ]}, ]}
尝试#2
根据错误提示改用rules_set_registry定义:
from cerberus import Validator, schema_registry, rules_set_registry schema_registry.add("leaf", {"value": {"type": "integer", "required": True}}) rules_set_registry.add("tree", {"type": "dict", "anyof_schema": ["leaf", "tree"]}) v = Validator(schema = {"root": {"type": "dict", "schema": "tree"}}) v.validate({"root": {"value": 1}}) v.errors v.validate({"root": {"a": {"value": 1}}}) v.errors v.validate({"root": {"a": {"b": {"c": {"value": 1}}}}}) v.errors
输出结果:
False {'root': ['must be of dict type']}
所有测试用例均验证失败。
预期行为
以下所有文档应通过验证:
v = Validator(schema = {"root": {"type": "dict", "schema": "tree"}}) assert v.validate({"root": {"value": 1}}), v.errors assert v.validate({"root": {"a": {"value": 1}}}), v.errors assert v.validate({"root": {"a": {"b": {"c": {"value": 1}}}}}), v.errors
正确实现方案
问题核心是递归规则的定义逻辑和引用方式错误,正确建模方式如下:
from cerberus import Validator, rules_set_registry, schema_registry # 注册叶子节点Schema:必须包含整数类型的value字段 schema_registry.add("leaf", {"value": {"type": "integer", "required": True}}) # 注册树形递归规则集:节点二选一 rules_set_registry.add( "tree", { "anyof": [ # 情况1:节点是叶子节点,匹配leaf Schema {"schema": "leaf"}, # 情况2:节点是分支节点,所有子节点需符合tree规则 {"valuesrules": {"rules_set": "tree"}} ] } ) # 定义根节点验证规则:必须是符合tree规则的字典 validator = Validator({"root": {"type": "dict", "rules_set": "tree"}}) # 测试验证 assert validator.validate({"root": {"value": 1}}), validator.errors assert validator.validate({"root": {"a": {"value": 1}}}), validator.errors assert validator.validate({"root": {"a": {"b": {"c": {"value": 1}}}}}), validator.errors print("所有测试用例验证通过")
关键说明
- 用
rules_set实现递归:Cerberus规则集支持自引用,而schema_registry不支持直接递归引用自身。 - 分支节点用
valuesrules:指定分支节点下所有子节点都必须符合tree规则,实现任意深度的递归验证。 anyof区分节点类型:明确节点要么是叶子节点,要么是分支节点,覆盖所有合法情况。
内容的提问来源于stack exchange,提问作者Marc Carrère
相关产品推荐
相关产品推荐

