原文标题:JSON Schema
作者:Pydantic 文档贡献者
来源:Pydantic 官方文档
原文:https://pydantic.dev/docs/validation/latest/concepts/json_schema/
页面标示的规范:JSON Schema Draft 2020-12、OpenAPI 3.1.0
Pydantic 能从模型和 Python 类型生成 JSON Schema,并按字段或模型定制生成结果。首先要区分两种输出:JSON Schema 描述数据形状和约束;序列化 JSON 则是某个模型实例的数据。它们不是同一个东西。
生成模型或任意类型的 Schema
对 Pydantic 模型调用 BaseModel.model_json_schema(),会得到可 JSON 化的 Python 字典。需要 JSON 文本时,再用 json.dumps() 序列化这个字典。TypeAdapter.json_schema() 可以为任意受支持的类型生成同类结果,比如 list[int]、联合类型,或由若干模型组成的类型。
import json
from pydantic import BaseModel, Field, TypeAdapter
class Address(BaseModel):
city: str
postal_code: str = Field(alias='postalCode')
class User(BaseModel):
name: str
age: int = Field(gt=0, description='Age in years')
address: Address
model_schema = User.model_json_schema()
print(json.dumps(model_schema, indent=2))
list_schema = TypeAdapter(list[int]).json_schema()
print(list_schema)
嵌套模型通常进入根 Schema 的 defs * *,字段通过 * *ref 指向定义。默认情况下,Schema 使用字段别名作为属性名;如果接口契约要使用模型内部字段名,可传 by_alias=False。模型的说明可以来自类文档字符串,字段说明和元数据可由 Field() 提供。
实例序列化使用的是另一组方法:model_dump_json() 序列化 BaseModel 实例;TypeAdapter.dump_json() 序列化适配类型的实例。前者返回 JSON 字符串,后者返回字节。不要把这些序列化 API 当作 Schema 生成方法。
根据输入验证或输出序列化选择模式
model_json_schema() 和 TypeAdapter.json_schema() 都接受 mode 参数。默认的 validation 模式描述 Pydantic 在输入校验时接受的数据形状;serialization 模式描述模型输出的数据形状。当一个 Python 类型的输入和输出表示不同,两个模式的 Schema 也会不同。
官方示例以 Decimal 为例:验证模式允许数字或符合十进制模式的字符串;序列化模式则描述字符串输出。设计请求体和响应体契约时,应根据具体方向选模式,而不是假设一种 Schema 同时覆盖两者。
from decimal import Decimal
from pydantic import BaseModel
class Price(BaseModel):
amount: Decimal
request_schema = Price.model_json_schema(mode='validation')
response_schema = Price.model_json_schema(mode='serialization')
如果需要将多个根模型及其子模型放进一个顶层 Schema,可用 models_json_schema(),并为每个模型指定模式:
from pydantic import BaseModel
from pydantic.json_schema import models_json_schema
class Item(BaseModel):
name: str
class Health(BaseModel):
ok: bool
_, api_schema = models_json_schema(
[(Item, 'validation'), (Health, 'validation')],
title='Example API',
)
该方法会在 $defs 中汇总相关模型定义。使用前要确认消费端期待的是这种多模型定义文档,还是每个端点各自独立的根 Schema。
为单个字段补充接口元数据
字段层级的 Schema 通常通过 Field() 定制。常用的 Schema 元数据包括 title、description、examples 和 json_schema_extra;字段约束如 gt、max_length 等也会在适用时转化为 JSON Schema 约束。field_title_generator 可以按字段名与字段信息生成标题。
from pydantic import BaseModel, Field
class Product(BaseModel):
sku: str = Field(
title='Product code',
description='Stable identifier used by the catalog',
)
quantity: int = Field(gt=0, examples=[3])
json_schema_extra 可接收字典,为生成的字段或模型 Schema 补充属性;也可接收函数,直接修改 Schema 字典。例如,在确有契约需求时,可以从生成结果中移除 default。这只修改文档描述;若运行时仍有默认值,移除 Schema 中的默认字段不会改变模型行为。
从 Pydantic 2.9 起,附加在嵌套 Annotated 类型上的 json_schema_extra 字典会合并。例如内外两层分别提供 key1 和 key2 时,结果可以同时包含两者。文档说明当前不支持把字典和 callable 两种配置混合组合。
定制模型标题与通用字段标题
模型配置可设置 title、json_schema_extra、json_schema_mode_override、field_title_generator 和 model_title_generator。字段标题生成器可只设在某个字段上,也可在模型配置中应用于全部字段;模型标题生成器接收模型类并返回标题。
from pydantic import BaseModel, ConfigDict
def make_model_title(model: type) -> str:
return f'API-{model.__name__}'
class Account(BaseModel):
model_config = ConfigDict(
field_title_generator=lambda field_name, field_info: field_name.upper(),
model_title_generator=make_model_title,
)
user_id: int
display_name: str
选择字段或模型级扩展,适用于少数字段、模型或自定义类型;若要改变整套生成策略,则可改用全局生成器。
对自定义类型覆盖或省略 Schema
WithJsonSchema 可以为某个类型直接提供 Schema,适合 Pydantic 默认无法生成 JSON Schema 的类型。它会覆盖该类型完整的生成 Schema,因此替代定义应包含所需的全部信息,例如 type。官方文档建议优先考虑 WithJsonSchema,它比自定义 __get_pydantic_json_schema__() 更简单,也较不容易出错。
from typing import Annotated
from pydantic import BaseModel, WithJsonSchema
SmallInteger = Annotated[
int,
WithJsonSchema({'type': 'integer', 'examples': [1, 0, -1]}),
]
class Counter(BaseModel):
value: SmallInteger
SkipJsonSchema 可从生成结果中省略某个字段或字段 Schema 的一部分。它只影响 JSON Schema 的呈现;它不是字段访问控制,也不会自动改变运行时验证、序列化或权限策略。
更复杂的自定义类型可实现 __get_pydantic_core_schema__() 来定义验证和序列化使用的核心 Schema,也可实现 __get_pydantic_json_schema__() 来修改其 JSON Schema。后者只改变 Schema,不改变用于验证和序列化的 core schema。对 Annotated 元数据,handler 可先取得内层生成的 Schema,再做修改;替换整个核心 Schema 时则要自行提供完整定义。除非确有必要,优先选用标准的字段元数据、WithJsonSchema 或 SkipJsonSchema。
用 GenerateJsonSchema 调整全局输出
要改变全局生成过程,可以继承 GenerateJsonSchema,覆盖其中的生成步骤,再把自定义类传给 model_json_schema() 或 TypeAdapter.json_schema() 的 schema_generator 参数。下面的示例沿用默认生成过程,只改根标题并显式输出当前 dialect:
from pydantic import BaseModel
from pydantic.json_schema import GenerateJsonSchema
class ApiSchemaGenerator(GenerateJsonSchema):
def generate(self, schema, mode='validation'):
result = super().generate(schema, mode=mode)
result['title'] = 'Public API'
result['$schema'] = self.schema_dialect
return result
class Event(BaseModel):
event_id: int
schema = Event.model_json_schema(schema_generator=ApiSchemaGenerator)
自定义生成器还可覆盖排序逻辑、处理无法生成 JSON Schema 的字段等。默认情况下,Pydantic 递归地按键名排序 Schema,但会保留 properties 中模型字段的定义顺序。全局改写能力较强,因此需要为变更后的契约留出清晰的维护边界。
调整 $ref 前缀与定义位置
通过生成方法的 ref_template 参数可以改变 $ref** 字符串的模板,例如改成 **#/components/schemas/{model}**。但 Pydantic 仍把定义放在 **$defs 中;只改引用前缀不会自动将 $defs 搬到 OpenAPI 文档的 components.schemas。生成后若目标格式要求不同的定义位置,还必须在组装 API 文档时处理定义树与所有引用之间的一致性。
schema = User.model_json_schema(
ref_template='#/components/schemas/{model}'
)
适配目标规范并核对版本
页面介绍的主要输出规范是 JSON Schema Draft 2020-12 与 OpenAPI 3.1.0。Python 类型、约束与自定义类型会被映射为 JSON Schema 的核心类型、验证关键字或 format 扩展。可选值、联合类型、列表和嵌套模型都会以相应的 null、anyOf、items、defs * *与 * *ref 结构体现。
使用映射表时要留意页面自身的例子存在不一致:Decimal 一节的验证/序列化示例将序列化表示为字符串,通用说明也说 Decimal 暴露为字符串;但同页较早的类型映射表把受约束 Decimal 列作 number。位置参数元组等类型的表格说明也需要结合目标 OpenAPI 版本与实际生成结果判断。不要把旧版消费者对 OpenAPI 3.0 的限制直接套用到 3.1;应固定项目实际安装的 Pydantic 版本,生成 Schema 后再按目标规范验证。
还有几项边界值得保留:
- Optional 字段的 Schema 会说明 null 可作为值;是否必填与是否可为空是两个不同的问题。
- 使用子模型时,Pydantic 通常把其定义放在 $defs 并引用;对子模型应用自定义标题、说明或默认值后,某些场景会递归内嵌。
- EmailStr 示例需要安装 email-validator 依赖才能使用。
- Schema 中的 examples 是公开的说明数据,不要放真实凭据或个人信息。
- writeOnly: true 是供 Schema 消费者理解字段用途的提示,不会加密字段内容。
页面页脚标示 © Pydantic Services Inc. 2025 to present;正文未列出一份单独的文章转载许可。页面路径使用 latest,并未给出一个固定的 Pydantic 软件版本,因此 API 和映射需要结合项目锁定版本核对。











暂无评论内容