You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:45:35