如何在Pydantic中让至少一个必填的属性组体现在Schema中
实现Pydantic模型“至少一个属性必填”的JSON Schema约束
当然可以实现,需要同时处理运行时校验和JSON Schema的自定义扩展。下面分Pydantic v1和v2两个主流版本给出具体实现方案:
Pydantic v2 实现方式
Pydantic v2提供了更灵活的Schema扩展能力,推荐结合model_validator(替代v1的root_validator)和model_config里的json_schema_extra来实现:
from pydantic import BaseModel, model_validator from typing import Optional class MyModel(BaseModel): a: Optional[str] = None b: Optional[int] = None c: Optional[bool] = None @model_validator(mode='after') def check_at_least_one_field(self): if not any([self.a, self.b, self.c]): raise ValueError("必须提供a、b、c中的至少一个属性") return self model_config = { "json_schema_extra": { "anyOf": [ {"required": ["a"]}, {"required": ["b"]}, {"required": ["c"]} ] } }
说明
model_validator(mode='after')会在字段校验完成后执行,确保实例至少有一个属性非空,处理运行时的校验逻辑。json_schema_extra中添加的anyOf规则,会被合并到生成的JSON Schema里,告诉Schema校验器:只要满足“必填a”“必填b”“必填c”中的任意一项即可,完美匹配“至少一个必填”的需求。
如果你的场景允许属性存在但值为null,可以把anyOf里的规则调整为检查属性非空,比如:
"anyOf": [ {"properties": {"a": {"not": {"type": "null"}}}, "required": ["a"]}, {"properties": {"b": {"not": {"type": "null"}}}, "required": ["b"]}, {"properties": {"c": {"not": {"type": "null"}}}, "required": ["c"]} ]
Pydantic v1 实现方式
在v1中,使用root_validator做运行时校验,同时通过Config类的schema_extra扩展Schema:
from pydantic import BaseModel, root_validator from typing import Optional class MyModel(BaseModel): a: Optional[str] = None b: Optional[int] = None c: Optional[bool] = None @root_validator(pre=False) def check_at_least_one_field(cls, values): if not any(values.values()): raise ValueError("必须提供a、b、c中的至少一个属性") return values class Config: schema_extra = { "anyOf": [ {"required": ["a"]}, {"required": ["b"]}, {"required": ["c"]} ] }
说明
root_validator(pre=False)确保在字段基础校验完成后再检查属性非空。schema_extra中的anyOf规则会被注入到生成的JSON Schema中,让支持Schema的工具能识别这个约束。
验证生成的Schema
以v2为例,生成的JSON Schema会包含如下关键片段:
{ "type": "object", "properties": { "a": {"type": "string"}, "b": {"type": "integer"}, "c": {"type": "boolean"} }, "anyOf": [ {"required": ["a"]}, {"required": ["b"]}, {"required": ["c"]} ] }
这个Schema会被所有符合JSON Schema规范的工具识别,确保输入至少包含a、b、c中的一个属性。
内容的提问来源于stack exchange,提问作者Timothy Bowen
相关产品推荐
相关产品推荐

