JSON Schema
API 文档
Pydantic 允许根据模型自动创建和自定义 JSON schema。生成的 JSON schema 兼容以下规范:
生成 JSON Schema¶
使用以下函数生成 JSON schema:
BaseModel.model_json_schema
返回一个模型 schema 的可 JSON 化字典。TypeAdapter.json_schema
返回一个适配类型的 schema 的可 JSON 化字典。
注意
这些方法不应与 BaseModel.model_dump_json
和 TypeAdapter.dump_json
混淆,后两者分别用于序列化模型或适配类型的实例。这些方法返回的是 JSON 字符串。相比之下,BaseModel.model_json_schema
和 TypeAdapter.json_schema
分别返回一个表示模型或适配类型 JSON schema 的可 JSON 化字典。
关于 JSON schema 的“可 JSON 化”性质
关于 model_json_schema
结果的“可 JSON 化”性质,对某个 BaseModel
m
调用 json.dumps(m.model_json_schema())
会返回一个有效的 JSON 字符串。同样,对于 TypeAdapter.json_schema
,调用 json.dumps(TypeAdapter(<some_type>).json_schema())
也会返回一个有效的 JSON 字符串。
提示
Pydantic 对两者都提供支持:
第一种方法的作用域通常更窄,允许在更具体的情况和类型下自定义 JSON schema。第二种方法的作用域通常更广,允许对整个 JSON schema 生成过程进行自定义。两种方法都可以实现相同的效果,但根据您的使用场景,其中一种方法可能比另一种提供更简单的解决方案。
以下是一个从 BaseModel
生成 JSON schema 的示例:
import json
from enum import Enum
from typing import Annotated, Union
from pydantic import BaseModel, Field
from pydantic.config import ConfigDict
class FooBar(BaseModel):
count: int
size: Union[float, None] = None
class Gender(str, Enum):
male = 'male'
female = 'female'
other = 'other'
not_given = 'not_given'
class MainModel(BaseModel):
"""
This is the description of the main model
"""
model_config = ConfigDict(title='Main')
foo_bar: FooBar
gender: Annotated[Union[Gender, None], Field(alias='Gender')] = None
snap: int = Field(
default=42,
title='The Snap',
description='this is the value of snap',
gt=30,
lt=50,
)
main_model_schema = MainModel.model_json_schema() # (1)!
print(json.dumps(main_model_schema, indent=2)) # (2)!
JSON 输出
{
"$defs": {
"FooBar": {
"properties": {
"count": {
"title": "Count",
"type": "integer"
},
"size": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Size"
}
},
"required": [
"count"
],
"title": "FooBar",
"type": "object"
},
"Gender": {
"enum": [
"male",
"female",
"other",
"not_given"
],
"title": "Gender",
"type": "string"
}
},
"description": "This is the description of the main model",
"properties": {
"foo_bar": {
"$ref": "#/$defs/FooBar"
},
"Gender": {
"anyOf": [
{
"$ref": "#/$defs/Gender"
},
{
"type": "null"
}
],
"default": null
},
"snap": {
"default": 42,
"description": "this is the value of snap",
"exclusiveMaximum": 50,
"exclusiveMinimum": 30,
"title": "The Snap",
"type": "integer"
}
},
"required": [
"foo_bar"
],
"title": "Main",
"type": "object"
}
- 这将生成一个
MainModel
schema 的“可 JSON 化”字典。 - 对 schema 字典调用
json.dumps
会生成一个 JSON 字符串。
import json
from enum import Enum
from typing import Annotated
from pydantic import BaseModel, Field
from pydantic.config import ConfigDict
class FooBar(BaseModel):
count: int
size: float | None = None
class Gender(str, Enum):
male = 'male'
female = 'female'
other = 'other'
not_given = 'not_given'
class MainModel(BaseModel):
"""
This is the description of the main model
"""
model_config = ConfigDict(title='Main')
foo_bar: FooBar
gender: Annotated[Gender | None, Field(alias='Gender')] = None
snap: int = Field(
default=42,
title='The Snap',
description='this is the value of snap',
gt=30,
lt=50,
)
main_model_schema = MainModel.model_json_schema() # (1)!
print(json.dumps(main_model_schema, indent=2)) # (2)!
JSON 输出
{
"$defs": {
"FooBar": {
"properties": {
"count": {
"title": "Count",
"type": "integer"
},
"size": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"title": "Size"
}
},
"required": [
"count"
],
"title": "FooBar",
"type": "object"
},
"Gender": {
"enum": [
"male",
"female",
"other",
"not_given"
],
"title": "Gender",
"type": "string"
}
},
"description": "This is the description of the main model",
"properties": {
"foo_bar": {
"$ref": "#/$defs/FooBar"
},
"Gender": {
"anyOf": [
{
"$ref": "#/$defs/Gender"
},
{
"type": "null"
}
],
"default": null
},
"snap": {
"default": 42,
"description": "this is the value of snap",
"exclusiveMaximum": 50,
"exclusiveMinimum": 30,
"title": "The Snap",
"type": "integer"
}
},
"required": [
"foo_bar"
],
"title": "Main",
"type": "object"
}
- 这将生成一个
MainModel
schema 的“可 JSON 化”字典。 - 对 schema 字典调用
json.dumps
会生成一个 JSON 字符串。
TypeAdapter
类允许您创建一个对象,该对象具有用于验证、序列化和为任意类型生成 JSON schema 的方法。这完全替代了 Pydantic V1 中的 schema_of
(现已弃用)。
以下是一个从 TypeAdapter
生成 JSON schema 的示例:
from pydantic import TypeAdapter
adapter = TypeAdapter(list[int])
print(adapter.json_schema())
#> {'items': {'type': 'integer'}, 'type': 'array'}
您还可以为 BaseModel
和 TypeAdapter
的组合生成 JSON schema,如下例所示:
import json
from typing import Union
from pydantic import BaseModel, TypeAdapter
class Cat(BaseModel):
name: str
color: str
class Dog(BaseModel):
name: str
breed: str
ta = TypeAdapter(Union[Cat, Dog])
ta_schema = ta.json_schema()
print(json.dumps(ta_schema, indent=2))
JSON 输出
{
"$defs": {
"Cat": {
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"color": {
"title": "Color",
"type": "string"
}
},
"required": [
"name",
"color"
],
"title": "Cat",
"type": "object"
},
"Dog": {
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"breed": {
"title": "Breed",
"type": "string"
}
},
"required": [
"name",
"breed"
],
"title": "Dog",
"type": "object"
}
},
"anyOf": [
{
"$ref": "#/$defs/Cat"
},
{
"$ref": "#/$defs/Dog"
}
]
}
配置 JsonSchemaMode
¶
通过 model_json_schema
和 TypeAdapter.json_schema
方法中的 mode
参数来指定 JSON schema 的生成模式。默认情况下,该模式设置为 'validation'
,它会生成一个与模型验证 schema 对应的 JSON schema。
JsonSchemaMode
是一个类型别名,表示 mode
参数可用的选项:
'validation'
'serialization'
以下是一个示例,说明如何指定 mode
参数,以及它如何影响生成的 JSON schema:
from decimal import Decimal
from pydantic import BaseModel
class Model(BaseModel):
a: Decimal = Decimal('12.34')
print(Model.model_json_schema(mode='validation'))
"""
{
'properties': {
'a': {
'anyOf': [
{'type': 'number'},
{
'pattern': '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$',
'type': 'string',
},
],
'default': '12.34',
'title': 'A',
}
},
'title': 'Model',
'type': 'object',
}
"""
print(Model.model_json_schema(mode='serialization'))
"""
{
'properties': {
'a': {
'default': '12.34',
'pattern': '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$',
'title': 'A',
'type': 'string',
}
},
'title': 'Model',
'type': 'object',
}
"""
自定义 JSON Schema¶
生成的 JSON schema 可以在字段级别和模型级别通过以下方式进行自定义:
- 使用
Field
构造函数进行字段级自定义 - 使用
model_config
进行模型级自定义
在字段和模型级别,您都可以使用 json_schema_extra
选项向 JSON schema 添加额外信息。下文的使用 json_schema_extra
部分提供了有关此选项的更多详细信息。
对于自定义类型,Pydantic 提供了其他工具来自定义 JSON schema 的生成:
字段级自定义¶
或者,可以使用 Field
函数来提供有关字段和验证的额外信息。
一些字段参数专门用于自定义生成的 JSON Schema:
title
: 字段的标题。description
: 字段的描述。examples
: 字段的示例。json_schema_extra
: 要添加到字段中的额外 JSON Schema 属性。field_title_generator
: 一个函数,根据字段名称和信息以编程方式设置字段标题。
这是一个示例:
import json
from pydantic import BaseModel, EmailStr, Field, SecretStr
class User(BaseModel):
age: int = Field(description='Age of the user')
email: EmailStr = Field(examples=['[email protected]'])
name: str = Field(title='Username')
password: SecretStr = Field(
json_schema_extra={
'title': 'Password',
'description': 'Password of the user',
'examples': ['123456'],
}
)
print(json.dumps(User.model_json_schema(), indent=2))
JSON 输出
{
"properties": {
"age": {
"description": "Age of the user",
"title": "Age",
"type": "integer"
},
"email": {
"examples": [
"[email protected]"
],
"format": "email",
"title": "Email",
"type": "string"
},
"name": {
"title": "Username",
"type": "string"
},
"password": {
"description": "Password of the user",
"examples": [
"123456"
],
"format": "password",
"title": "Password",
"type": "string",
"writeOnly": true
}
},
"required": [
"age",
"email",
"name",
"password"
],
"title": "User",
"type": "object"
}
未强制执行的 Field
约束¶
如果 Pydantic 发现约束未被强制执行,将会引发错误。如果您想强制该约束出现在 schema 中,即使在解析时未进行检查,您可以使用原始 schema 属性名称作为可变参数传递给 Field
:
from pydantic import BaseModel, Field, PositiveInt
try:
# this won't work since `PositiveInt` takes precedence over the
# constraints defined in `Field`, meaning they're ignored
class Model(BaseModel):
foo: PositiveInt = Field(lt=10)
except ValueError as e:
print(e)
# if you find yourself needing this, an alternative is to declare
# the constraints in `Field` (or you could use `conint()`)
# here both constraints will be enforced:
class ModelB(BaseModel):
# Here both constraints will be applied and the schema
# will be generated correctly
foo: int = Field(gt=0, lt=10)
print(ModelB.model_json_schema())
"""
{
'properties': {
'foo': {
'exclusiveMaximum': 10,
'exclusiveMinimum': 0,
'title': 'Foo',
'type': 'integer',
}
},
'required': ['foo'],
'title': 'ModelB',
'type': 'object',
}
"""
您也可以通过 typing.Annotated
使用 Field
构造函数来指定 JSON schema 的修改:
import json
from typing import Annotated
from uuid import uuid4
from pydantic import BaseModel, Field
class Foo(BaseModel):
id: Annotated[str, Field(default_factory=lambda: uuid4().hex)]
name: Annotated[str, Field(max_length=256)] = Field(
'Bar', title='CustomName'
)
print(json.dumps(Foo.model_json_schema(), indent=2))
JSON 输出
{
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"default": "Bar",
"maxLength": 256,
"title": "CustomName",
"type": "string"
}
},
"title": "Foo",
"type": "object"
}
以编程方式生成字段标题¶
field_title_generator
参数可用于根据字段的名称和信息以编程方式生成字段的标题。
请看以下示例:
import json
from pydantic import BaseModel, Field
from pydantic.fields import FieldInfo
def make_title(field_name: str, field_info: FieldInfo) -> str:
return field_name.upper()
class Person(BaseModel):
name: str = Field(field_title_generator=make_title)
age: int = Field(field_title_generator=make_title)
print(json.dumps(Person.model_json_schema(), indent=2))
"""
{
"properties": {
"name": {
"title": "NAME",
"type": "string"
},
"age": {
"title": "AGE",
"type": "integer"
}
},
"required": [
"name",
"age"
],
"title": "Person",
"type": "object"
}
"""
模型级自定义¶
您还可以使用模型配置在模型上自定义 JSON schema 的生成。具体来说,以下配置选项是相关的:
使用 json_schema_extra
¶
json_schema_extra
选项可用于向 JSON schema 添加额外信息,无论是在字段级别还是模型级别。您可以向 json_schema_extra
传递一个 dict
或一个 Callable
。
使用字典形式的 json_schema_extra
¶
您可以向 json_schema_extra
传递一个 dict
来为 JSON schema 添加额外信息:
import json
from pydantic import BaseModel, ConfigDict
class Model(BaseModel):
a: str
model_config = ConfigDict(json_schema_extra={'examples': [{'a': 'Foo'}]})
print(json.dumps(Model.model_json_schema(), indent=2))
JSON 输出
{
"examples": [
{
"a": "Foo"
}
],
"properties": {
"a": {
"title": "A",
"type": "string"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
使用可调用对象形式的 json_schema_extra
¶
您可以向 json_schema_extra
传递一个 Callable
,用一个函数来修改 JSON schema:
import json
from pydantic import BaseModel, Field
def pop_default(s):
s.pop('default')
class Model(BaseModel):
a: int = Field(default=1, json_schema_extra=pop_default)
print(json.dumps(Model.model_json_schema(), indent=2))
JSON 输出
{
"properties": {
"a": {
"title": "A",
"type": "integer"
}
},
"title": "Model",
"type": "object"
}
合并 json_schema_extra
¶
从 v2.9 开始,Pydantic 会合并来自注解类型的 json_schema_extra
字典。与之前的覆盖行为相比,这种模式提供了一种更具累加性的合并方法。这对于在多个类型之间重用 json schema 额外信息的场景非常有用。
我们认为这一更改主要是一个 bug 修复,因为它解决了 BaseModel
和 TypeAdapter
实例之间在 json_schema_extra
合并行为上的无意差异——更多细节请参见此 issue。
import json
from typing import Annotated
from typing_extensions import TypeAlias
from pydantic import Field, TypeAdapter
ExternalType: TypeAlias = Annotated[
int, Field(json_schema_extra={'key1': 'value1'})
]
ta = TypeAdapter(
Annotated[ExternalType, Field(json_schema_extra={'key2': 'value2'})]
)
print(json.dumps(ta.json_schema(), indent=2))
"""
{
"key1": "value1",
"key2": "value2",
"type": "integer"
}
"""
import json
from typing import Annotated
from typing import TypeAlias
from pydantic import Field, TypeAdapter
ExternalType: TypeAlias = Annotated[
int, Field(json_schema_extra={'key1': 'value1'})
]
ta = TypeAdapter(
Annotated[ExternalType, Field(json_schema_extra={'key2': 'value2'})]
)
print(json.dumps(ta.json_schema(), indent=2))
"""
{
"key1": "value1",
"key2": "value2",
"type": "integer"
}
"""
注意
我们不再(也从未完全)支持混合使用 dict
和 callable
类型的 json_schema_extra
规范。如果这是您的使用场景所必需的,请在 pydantic 提交一个 issue并解释您的情况——我们很乐意在有说服力的案例出现时重新考虑这个决定。
WithJsonSchema
注解¶
提示
对于自定义类型,推荐使用 WithJsonSchema
,而不是实现 __get_pydantic_json_schema__
,因为它更简单且不易出错。
WithJsonSchema
注解可用于覆盖给定类型生成的(基础)JSON schema,而无需在类型本身上实现 __get_pydantic_core_schema__
或 __get_pydantic_json_schema__
。请注意,这将覆盖该字段的整个 JSON Schema 生成过程(在下面的示例中,也需要提供 'type'
)。
import json
from typing import Annotated
from pydantic import BaseModel, WithJsonSchema
MyInt = Annotated[
int,
WithJsonSchema({'type': 'integer', 'examples': [1, 0, -1]}),
]
class Model(BaseModel):
a: MyInt
print(json.dumps(Model.model_json_schema(), indent=2))
JSON 输出
{
"properties": {
"a": {
"examples": [
1,
0,
-1
],
"title": "A",
"type": "integer"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
注意
您可能会想使用 WithJsonSchema
注解来微调附加了验证器的字段的 JSON Schema。相反,建议使用json_schema_input_type
参数。
SkipJsonSchema
注解¶
SkipJsonSchema
注解可用于从生成的 JSON schema 中跳过一个包含的字段(或字段规范的一部分)。更多详细信息请参见 API 文档。
实现 __get_pydantic_core_schema__
¶
自定义类型(用作 field_name: TheType
或 field_name: Annotated[TheType, ...]
)以及 Annotated
元数据(用作 field_name: Annotated[int, SomeMetadata]
)可以通过实现 __get_pydantic_core_schema__
来修改或覆盖生成的 schema。该方法接收两个位置参数:
- 与此类型对应的类型注解(因此在
TheType[T][int]
的情况下,它将是TheType[int]
)。 - 一个处理器/回调函数,用于调用
__get_pydantic_core_schema__
的下一个实现者。
处理器系统的工作方式与包装字段验证器类似。在这种情况下,输入是类型,输出是 core_schema
。
以下是一个自定义类型覆盖生成的 core_schema
的示例:
from dataclasses import dataclass
from typing import Any
from pydantic_core import core_schema
from pydantic import BaseModel, GetCoreSchemaHandler
@dataclass
class CompressedString:
dictionary: dict[int, str]
text: list[int]
def build(self) -> str:
return ' '.join([self.dictionary[key] for key in self.text])
@classmethod
def __get_pydantic_core_schema__(
cls, source: type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
assert source is CompressedString
return core_schema.no_info_after_validator_function(
cls._validate,
core_schema.str_schema(),
serialization=core_schema.plain_serializer_function_ser_schema(
cls._serialize,
info_arg=False,
return_schema=core_schema.str_schema(),
),
)
@staticmethod
def _validate(value: str) -> 'CompressedString':
inverse_dictionary: dict[str, int] = {}
text: list[int] = []
for word in value.split(' '):
if word not in inverse_dictionary:
inverse_dictionary[word] = len(inverse_dictionary)
text.append(inverse_dictionary[word])
return CompressedString(
{v: k for k, v in inverse_dictionary.items()}, text
)
@staticmethod
def _serialize(value: 'CompressedString') -> str:
return value.build()
class MyModel(BaseModel):
value: CompressedString
print(MyModel.model_json_schema())
"""
{
'properties': {'value': {'title': 'Value', 'type': 'string'}},
'required': ['value'],
'title': 'MyModel',
'type': 'object',
}
"""
print(MyModel(value='fox fox fox dog fox'))
"""
value = CompressedString(dictionary={0: 'fox', 1: 'dog'}, text=[0, 0, 0, 1, 0])
"""
print(MyModel(value='fox fox fox dog fox').model_dump(mode='json'))
#> {'value': 'fox fox fox dog fox'}
由于 Pydantic 不知道如何为 CompressedString
生成 schema,如果您在其 __get_pydantic_core_schema__
方法中调用 handler(source)
,将会得到一个 pydantic.errors.PydanticSchemaGenerationError
错误。对于大多数自定义类型来说都是如此,因此您几乎从不希望为自定义类型调用 handler
。
对于 Annotated
元数据,过程大致相同,只是您通常可以调用 handler
来让 Pydantic 处理 schema 的生成。
from collections.abc import Sequence
from dataclasses import dataclass
from typing import Annotated, Any
from pydantic_core import core_schema
from pydantic import BaseModel, GetCoreSchemaHandler, ValidationError
@dataclass
class RestrictCharacters:
alphabet: Sequence[str]
def __get_pydantic_core_schema__(
self, source: type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
if not self.alphabet:
raise ValueError('Alphabet may not be empty')
schema = handler(
source
) # get the CoreSchema from the type / inner constraints
if schema['type'] != 'str':
raise TypeError('RestrictCharacters can only be applied to strings')
return core_schema.no_info_after_validator_function(
self.validate,
schema,
)
def validate(self, value: str) -> str:
if any(c not in self.alphabet for c in value):
raise ValueError(
f'{value!r} is not restricted to {self.alphabet!r}'
)
return value
class MyModel(BaseModel):
value: Annotated[str, RestrictCharacters('ABC')]
print(MyModel.model_json_schema())
"""
{
'properties': {'value': {'title': 'Value', 'type': 'string'}},
'required': ['value'],
'title': 'MyModel',
'type': 'object',
}
"""
print(MyModel(value='CBA'))
#> value='CBA'
try:
MyModel(value='XYZ')
except ValidationError as e:
print(e)
"""
1 validation error for MyModel
value
Value error, 'XYZ' is not restricted to 'ABC' [type=value_error, input_value='XYZ', input_type=str]
"""
到目前为止,我们一直在包装 schema,但如果您只想修改或忽略它,也可以做到。
要修改 schema,首先调用处理器,然后修改结果:
from typing import Annotated, Any
from pydantic_core import ValidationError, core_schema
from pydantic import BaseModel, GetCoreSchemaHandler
class SmallString:
def __get_pydantic_core_schema__(
self,
source: type[Any],
handler: GetCoreSchemaHandler,
) -> core_schema.CoreSchema:
schema = handler(source)
assert schema['type'] == 'str'
schema['max_length'] = 10 # modify in place
return schema
class MyModel(BaseModel):
value: Annotated[str, SmallString()]
try:
MyModel(value='too long!!!!!')
except ValidationError as e:
print(e)
"""
1 validation error for MyModel
value
String should have at most 10 characters [type=string_too_long, input_value='too long!!!!!', input_type=str]
"""
提示
请注意,您必须返回一个 schema,即使您只是在原地修改它。
要完全覆盖 schema,请不要调用处理器并返回您自己的 CoreSchema
:
from typing import Annotated, Any
from pydantic_core import ValidationError, core_schema
from pydantic import BaseModel, GetCoreSchemaHandler
class AllowAnySubclass:
def __get_pydantic_core_schema__(
self, source: type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
# we can't call handler since it will fail for arbitrary types
def validate(value: Any) -> Any:
if not isinstance(value, source):
raise ValueError(
f'Expected an instance of {source}, got an instance of {type(value)}'
)
return core_schema.no_info_plain_validator_function(validate)
class Foo:
pass
class Model(BaseModel):
f: Annotated[Foo, AllowAnySubclass()]
print(Model(f=Foo()))
#> f=None
class NotFoo:
pass
try:
Model(f=NotFoo())
except ValidationError as e:
print(e)
"""
1 validation error for Model
f
Value error, Expected an instance of <class '__main__.Foo'>, got an instance of <class '__main__.NotFoo'> [type=value_error, input_value=<__main__.NotFoo object at 0x0123456789ab>, input_type=NotFoo]
"""
实现 __get_pydantic_json_schema__
¶
您还可以实现 __get_pydantic_json_schema__
来修改或覆盖生成的 json schema。修改此方法仅影响 JSON schema——它不影响用于验证和序列化的核心 schema。
以下是修改生成的 JSON schema 的一个示例:
import json
from typing import Any
from pydantic_core import core_schema as cs
from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler, TypeAdapter
from pydantic.json_schema import JsonSchemaValue
class Person:
name: str
age: int
def __init__(self, name: str, age: int):
self.name = name
self.age = age
@classmethod
def __get_pydantic_core_schema__(
cls, source_type: Any, handler: GetCoreSchemaHandler
) -> cs.CoreSchema:
return cs.typed_dict_schema(
{
'name': cs.typed_dict_field(cs.str_schema()),
'age': cs.typed_dict_field(cs.int_schema()),
},
)
@classmethod
def __get_pydantic_json_schema__(
cls, core_schema: cs.CoreSchema, handler: GetJsonSchemaHandler
) -> JsonSchemaValue:
json_schema = handler(core_schema)
json_schema = handler.resolve_ref_schema(json_schema)
json_schema['examples'] = [
{
'name': 'John Doe',
'age': 25,
}
]
json_schema['title'] = 'Person'
return json_schema
print(json.dumps(TypeAdapter(Person).json_schema(), indent=2))
JSON 输出
{
"examples": [
{
"age": 25,
"name": "John Doe"
}
],
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"age": {
"title": "Age",
"type": "integer"
}
},
"required": [
"name",
"age"
],
"title": "Person",
"type": "object"
}
使用 field_title_generator
¶
field_title_generator
参数可用于根据字段的名称和信息以编程方式生成字段的标题。这与字段级别的 field_title_generator
类似,但 ConfigDict
选项将应用于该类的所有字段。
请看以下示例:
import json
from pydantic import BaseModel, ConfigDict
class Person(BaseModel):
model_config = ConfigDict(
field_title_generator=lambda field_name, field_info: field_name.upper()
)
name: str
age: int
print(json.dumps(Person.model_json_schema(), indent=2))
"""
{
"properties": {
"name": {
"title": "NAME",
"type": "string"
},
"age": {
"title": "AGE",
"type": "integer"
}
},
"required": [
"name",
"age"
],
"title": "Person",
"type": "object"
}
"""
使用 model_title_generator
¶
model_title_generator
配置选项与 field_title_generator
选项类似,但它应用于模型本身的标题,并接受模型类作为输入。
请看以下示例:
import json
from pydantic import BaseModel, ConfigDict
def make_title(model: type) -> str:
return f'Title-{model.__name__}'
class Person(BaseModel):
model_config = ConfigDict(model_title_generator=make_title)
name: str
age: int
print(json.dumps(Person.model_json_schema(), indent=2))
"""
{
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"age": {
"title": "Age",
"type": "integer"
}
},
"required": [
"name",
"age"
],
"title": "Title-Person",
"type": "object"
}
"""
JSON schema 类型¶
类型、自定义字段类型和约束(如 max_length
)将按照以下优先级顺序映射到相应的规范格式(当有等效可用时):
- JSON Schema Core
- JSON Schema Validation
- OpenAPI Data Types
- 标准的
format
JSON 字段用于为更复杂的string
子类型定义 Pydantic 扩展。
从 Python 或 Pydantic 到 JSON schema 的字段 schema 映射如下:
{{ schema_mappings_table }}
顶层 schema 生成¶
您还可以生成一个顶层的 JSON schema,它只在其 $defs
中包含模型列表和相关的子模型:
import json
from pydantic import BaseModel
from pydantic.json_schema import models_json_schema
class Foo(BaseModel):
a: str = None
class Model(BaseModel):
b: Foo
class Bar(BaseModel):
c: int
_, top_level_schema = models_json_schema(
[(Model, 'validation'), (Bar, 'validation')], title='My Schema'
)
print(json.dumps(top_level_schema, indent=2))
JSON 输出
{
"$defs": {
"Bar": {
"properties": {
"c": {
"title": "C",
"type": "integer"
}
},
"required": [
"c"
],
"title": "Bar",
"type": "object"
},
"Foo": {
"properties": {
"a": {
"default": null,
"title": "A",
"type": "string"
}
},
"title": "Foo",
"type": "object"
},
"Model": {
"properties": {
"b": {
"$ref": "#/$defs/Foo"
}
},
"required": [
"b"
],
"title": "Model",
"type": "object"
}
},
"title": "My Schema"
}
自定义 JSON Schema 生成过程¶
API 文档
如果您需要自定义 schema 生成,可以使用 schema_generator
,根据您的应用程序需要修改 GenerateJsonSchema
类。
可以用来生成 JSON schema 的各种方法都接受一个关键字参数 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema
,您可以将您的自定义子类传递给这些方法,以便使用您自己的方法来生成 JSON schema。
GenerateJsonSchema
实现了将类型的 pydantic-core
schema 转换为 JSON schema 的过程。按照设计,这个类将 JSON schema 的生成过程分解为更小的方法,这些方法可以在子类中轻松地被覆盖,以修改生成 JSON schema 的“全局”方法。
from pydantic import BaseModel
from pydantic.json_schema import GenerateJsonSchema
class MyGenerateJsonSchema(GenerateJsonSchema):
def generate(self, schema, mode='validation'):
json_schema = super().generate(schema, mode=mode)
json_schema['title'] = 'Customize title'
json_schema['$schema'] = self.schema_dialect
return json_schema
class MyModel(BaseModel):
x: int
print(MyModel.model_json_schema(schema_generator=MyGenerateJsonSchema))
"""
{
'properties': {'x': {'title': 'X', 'type': 'integer'}},
'required': ['x'],
'title': 'Customize title',
'type': 'object',
'$schema': 'https://json-schema.fullstack.org.cn/draft/2020-12/schema',
}
"""
下面是一种您可以用来从 schema 中排除任何没有有效 json schema 的字段的方法:
from typing import Callable
from pydantic_core import PydanticOmit, core_schema
from pydantic import BaseModel
from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
class MyGenerateJsonSchema(GenerateJsonSchema):
def handle_invalid_for_json_schema(
self, schema: core_schema.CoreSchema, error_info: str
) -> JsonSchemaValue:
raise PydanticOmit
def example_callable():
return 1
class Example(BaseModel):
name: str = 'example'
function: Callable = example_callable
instance_example = Example()
validation_schema = instance_example.model_json_schema(
schema_generator=MyGenerateJsonSchema, mode='validation'
)
print(validation_schema)
"""
{
'properties': {
'name': {'default': 'example', 'title': 'Name', 'type': 'string'}
},
'title': 'Example',
'type': 'object',
}
"""
from collections.abc import Callable
from pydantic_core import PydanticOmit, core_schema
from pydantic import BaseModel
from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
class MyGenerateJsonSchema(GenerateJsonSchema):
def handle_invalid_for_json_schema(
self, schema: core_schema.CoreSchema, error_info: str
) -> JsonSchemaValue:
raise PydanticOmit
def example_callable():
return 1
class Example(BaseModel):
name: str = 'example'
function: Callable = example_callable
instance_example = Example()
validation_schema = instance_example.model_json_schema(
schema_generator=MyGenerateJsonSchema, mode='validation'
)
print(validation_schema)
"""
{
'properties': {
'name': {'default': 'example', 'title': 'Name', 'type': 'string'}
},
'title': 'Example',
'type': 'object',
}
"""
JSON schema 排序¶
默认情况下,Pydantic 通过按字母顺序对键进行排序来递归地对 JSON schema 进行排序。值得注意的是,Pydantic 会跳过对 properties
键的值进行排序,以保留字段在模型中定义的顺序。
如果您想自定义此行为,可以在您的自定义 GenerateJsonSchema
子类中覆盖 sort
方法。以下示例使用一个无操作的 sort
方法来完全禁用排序,这反映在模型字段和 json_schema_extra
键的顺序被保留了:
import json
from typing import Optional
from pydantic import BaseModel, Field
from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
class MyGenerateJsonSchema(GenerateJsonSchema):
def sort(
self, value: JsonSchemaValue, parent_key: Optional[str] = None
) -> JsonSchemaValue:
"""No-op, we don't want to sort schema values at all."""
return value
class Bar(BaseModel):
c: str
b: str
a: str = Field(json_schema_extra={'c': 'hi', 'b': 'hello', 'a': 'world'})
json_schema = Bar.model_json_schema(schema_generator=MyGenerateJsonSchema)
print(json.dumps(json_schema, indent=2))
"""
{
"type": "object",
"properties": {
"c": {
"type": "string",
"title": "C"
},
"b": {
"type": "string",
"title": "B"
},
"a": {
"type": "string",
"c": "hi",
"b": "hello",
"a": "world",
"title": "A"
}
},
"required": [
"c",
"b",
"a"
],
"title": "Bar"
}
"""
import json
from pydantic import BaseModel, Field
from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
class MyGenerateJsonSchema(GenerateJsonSchema):
def sort(
self, value: JsonSchemaValue, parent_key: str | None = None
) -> JsonSchemaValue:
"""No-op, we don't want to sort schema values at all."""
return value
class Bar(BaseModel):
c: str
b: str
a: str = Field(json_schema_extra={'c': 'hi', 'b': 'hello', 'a': 'world'})
json_schema = Bar.model_json_schema(schema_generator=MyGenerateJsonSchema)
print(json.dumps(json_schema, indent=2))
"""
{
"type": "object",
"properties": {
"c": {
"type": "string",
"title": "C"
},
"b": {
"type": "string",
"title": "B"
},
"a": {
"type": "string",
"c": "hi",
"b": "hello",
"a": "world",
"title": "A"
}
},
"required": [
"c",
"b",
"a"
],
"title": "Bar"
}
"""
自定义 JSON Schema 中的 $ref
¶
$ref
的格式可以通过调用 model_json_schema()
或 model_dump_json()
并传入 ref_template
关键字参数来更改。定义总是存储在键 $defs
下,但可以为引用指定一个前缀。
当您需要扩展或修改 JSON schema 默认的定义位置时,这很有用。例如,在 OpenAPI 中:
import json
from pydantic import BaseModel
from pydantic.type_adapter import TypeAdapter
class Foo(BaseModel):
a: int
class Model(BaseModel):
a: Foo
adapter = TypeAdapter(Model)
print(
json.dumps(
adapter.json_schema(ref_template='#/components/schemas/{model}'),
indent=2,
)
)
JSON 输出
{
"$defs": {
"Foo": {
"properties": {
"a": {
"title": "A",
"type": "integer"
}
},
"required": [
"a"
],
"title": "Foo",
"type": "object"
}
},
"properties": {
"a": {
"$ref": "#/components/schemas/Foo"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
关于 JSON Schema 生成的杂项说明¶
Optional
字段的 JSON schema 表明允许null
值。Decimal
类型在 JSON schema 中(以及序列化时)被公开为字符串。- 由于
namedtuple
类型在 JSON 中不存在,模型的 JSON schema 不会保留namedtuple
为namedtuple
。 - 根据规范,使用的子模型会添加到
$defs
JSON 属性中并被引用。 - 带有修改(通过
Field
类)的子模型,如自定义标题、描述或默认值,会被递归地包含而不是被引用。 - 模型的
description
取自类的文档字符串或传递给Field
类的description
参数。 - 默认情况下,schema 是使用别名作为键生成的,但可以通过调用
model_json_schema()
或model_dump_json()
并传入by_alias=False
关键字参数来改用模型属性名称生成。