如何在Cerberus中创建自定义规范化规则?
实现Cerberus自定义PrimaryKey Coercer来扁平化Protobuf嵌套结构
我刚好处理过类似的Protobuf转MongoDB的结构规范化需求,这就给你一步步讲清楚怎么实现这个自定义coercer:
1. 编写自定义Coercer函数
核心逻辑就是从嵌套的team.id.value中提取ID值,然后返回{"value": "<some-id>"}的结构。还要考虑异常情况,避免结构不符合预期时出错:
def coerce_primarykey(value, field, error_handler): # 先检查输入结构是否符合预期 if isinstance(value, dict) and "id" in value and "value" in value["id"]: # 提取嵌套的ID值,返回目标结构 return {"value": value["id"]["value"]} else: # 如果结构不对,调用Cerberus的错误处理器抛出提示 error_handler(f"Invalid structure for field '{field}': expected dict with 'id.value', got {value}") # 也可以根据业务需求返回默认值,这里返回None示例 return None
2. 注册Coercer到Cerberus Validator
你有两种注册方式,选适合你的场景:
全局注册(所有Validator实例都能用)
from cerberus import Validator # 把自定义coercer绑定到"primarykey"标识上 Validator.coerce("primarykey", coerce_primarykey)
实例级注册(仅当前Validator实例可用)
v = Validator() v.coerce("primarykey", coerce_primarykey)
3. 调整Schema(可选但更稳妥)
你原来的schema里type设为了自定义的primarykey,这需要额外注册类型验证器。其实更简单的是把type改成dict(因为原始输入和转换后都是字典结构),这样不需要额外处理类型验证:
schema = { 'team': { 'type': 'dict', # 替换成原生dict类型,避免自定义类型的额外工作 'coerce': 'primarykey', 'data_relation': {'schema': 0, 'field': 'id'}, 'required': True, 'permanent': True, } }
如果坚持要用自定义primarykey类型,那还要加一个类型验证函数:
def validate_primarykey(field, value, error_handler): if not isinstance(value, dict) or "id" not in value or "value" not in value["id"]: error_handler(f"Field '{field}' must be a dict containing 'id.value'") # 注册自定义类型 Validator.types["primarykey"] = validate_primarykey
4. 测试验证效果
用你的测试数据跑一遍,看看结果是否符合预期:
test_data = { "team": { "id": {"value": "team-123"}, "random": "some-random-value" } } v = Validator(schema) if v.validate(test_data): print(v.document) # 输出: {"team": {"value": "team-123"}} else: print(v.errors) # 如果结构错误会输出提示
这样就能完美实现你要的扁平化转换,把嵌套的子消息转换成仅保留ID引用的结构啦。
内容的提问来源于stack exchange,提问作者Matthew Ellison
相关产品推荐
相关产品推荐

