如何将Pydantic中依赖字段的自定义校验映射到JSON Schema?
解决Pydantic跨字段校验映射到JSON Schema的问题
Pydantic默认不会自动将依赖其他字段的自定义校验逻辑转换为JSON Schema,因为这类跨字段约束不属于JSON Schema的标准单字段规则。你可以通过以下方式手动实现映射,比如用oneOf或$data关键字:
场景1:字段a是固定枚举值(用oneOf实现)
如果a的取值是有限的枚举值,oneOf是兼容性最好的方案,所有JSON Schema验证器都支持。
Pydantic v2 示例
from pydantic import BaseModel, Field, model_validator class A(BaseModel): a: int = Field(..., enum=[1, 2, 3]) b: list[int] @model_validator(mode='after') def check_b_length(self) -> 'A': if len(self.b) != self.a: raise ValueError(f"b的长度必须等于a的值 {self.a}") return self # 手动添加JSON Schema的oneOf约束 model_config = { "json_schema_extra": { "oneOf": [ {"properties": {"a": {"const": 1}, "b": {"minItems": 1, "maxItems": 1}}}, {"properties": {"a": {"const": 2}, "b": {"minItems": 2, "maxItems": 2}}}, {"properties": {"a": {"const": 3}, "b": {"minItems": 3, "maxItems": 3}}}, ] } } # 生成并查看Schema print(A.model_json_schema())
Pydantic v1 示例
from pydantic import BaseModel, Field, validator class A(BaseModel): a: int = Field(..., enum=[1, 2, 3]) b: list[int] @validator('b') def check_b_length(cls, v, values): if 'a' in values and len(v) != values['a']: raise ValueError(f"b的长度必须等于a的值 {values['a']}") return v class Config: schema_extra = { "oneOf": [ {"properties": {"a": {"const": 1}, "b": {"minItems": 1, "maxItems": 1}}}, {"properties": {"a": {"const": 2}, "b": {"minItems": 2, "maxItems": 2}}}, {"properties": {"a": {"const": 3}, "b": {"minItems": 3, "maxItems": 3}}}, ] } # 生成并查看Schema print(A.schema())
场景2:字段a是任意整数(用$data关键字)
如果a可以是任意整数,$data关键字能直接引用a的值来约束b的长度,但注意仅JSON Schema Draft 2019-09及更高版本支持该关键字,且部分验证器(如Python的jsonschema库)需要启用对应的draft版本。
Pydantic v2 示例
from pydantic import BaseModel, model_validator class A(BaseModel): a: int b: list[int] @model_validator(mode='after') def check_b_length(self) -> 'A': if len(self.b) != self.a: raise ValueError(f"b的长度必须等于a的值 {self.a}") return self model_config = { "json_schema_extra": { "properties": { "b": { "minItems": {"$data": "/a"}, "maxItems": {"$data": "/a"} } } } } # 生成Schema(需确保验证器支持Draft 2019-09+) print(A.model_json_schema())
动态扩展Schema(Pydantic v2进阶)
如果需要更灵活的Schema生成逻辑,可以自定义JSON Schema生成器:
from pydantic import BaseModel, model_validator, TypeAdapter from pydantic.json_schema import GenerateJsonSchema class A(BaseModel): a: int b: list[int] @model_validator(mode='after') def check_b_length(self) -> 'A': if len(self.b) != self.a: raise ValueError(f"b的长度必须等于a的值 {self.a}") return self class CustomSchemaGenerator(GenerateJsonSchema): def generate_obj_schema(self, model: type[BaseModel]) -> dict: schema = super().generate_obj_schema(model) if model is A: # 给b字段添加基于a的长度约束 schema['properties']['b']['minItems'] = {"$data": "/a"} schema['properties']['b']['maxItems'] = {"$data": "/a"} return schema # 用自定义生成器生成Schema adapter = TypeAdapter(A) custom_schema = adapter.json_schema(generator=CustomSchemaGenerator()) print(custom_schema)
关键说明
- Pydantic不会自动处理跨字段校验的Schema映射,必须手动扩展,因为这类逻辑不属于标准JSON Schema的单字段约束范畴。
oneOf兼容性最好,但仅适用于a取值有限的场景;$data更简洁,但依赖高版本JSON Schema支持。
内容的提问来源于stack exchange,提问作者charelf
相关产品推荐
相关产品推荐

