JSON Schema
API 文档
Pydantic 允许从模型自动创建和自定义 JSON 模式。生成的 JSON 模式符合以下规范:
- JSON 模式草案 2020-12
- OpenAPI 规范 v3.1.0。
生成 JSON 模式¶
使用以下功能生成 JSON 模式:
BaseModel.model_json_schema
返回模型架构的可 JSON 化字典。TypeAdapter.json_schema
返回已适配类型的模式的可 json 化字典。
注意,这些方法不应与 BaseModel.model_dump_json
和 TypeAdapter.dump_json
混淆,它们分别序列化模型或已适配类型的实例。这些方法返回 JSON 字符串。相比之下, BaseModel.model_json_schema
和 TypeAdapter.json_schema
返回一个可 json 化的字典,表示模型或已适配类型的 JSON 模式。
注释
“关于 JSON 模式的”可 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 同时支持以下两种方式:
The first approach generally has a more narrow scope, allowing for customization of the JSON schema for more specific cases and types. The second approach generally has a more broad scope, allowing for customization of the JSON schema generation process overall. The same effects can be achieved with either approach, but depending on your use case, one approach might offer a more simple solution than the other.
以下是从一个 BaseModel
生成 JSON 模式的示例:
import json
from enum import Enum
from typing import Union
from typing_extensions import Annotated
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(
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)!
"""
{
"$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"
}
"""
-
这会生成一个可 JSON 化的字典,其中包含
MainModel
的模式。 -
在模式字典上调用
json.dumps
会产生一个 JSON 字符串。
TypeAdapter 类允许你创建一个具有方法的对象,用于验证、序列化和为任意类型生成 JSON 模式。这完全取代了 Pydantic V1 中的 schema_of
(现在已弃用)。
以下是从 TypeAdapter
生成 JSON 模式的示例:
from typing import List
from pydantic import TypeAdapter
adapter = TypeAdapter(List[int])
print(adapter.json_schema())
#> {'items': {'type': 'integer'}, 'type': 'array'}
你还可以为 BaseModel
s 和 TypeAdapter
s 的组合生成 JSON 模式,如下例所示:
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))
"""
{
"$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 模式生成模式。默认情况下,模式设置为 'validation'
,它生成与模型验证模式相对应的 JSON 模式。
JsonSchemaMode
是一个类型别名,它表示 mode
参数的可用选项:
'validation'
'serialization'
以下是指定 mode
参数的示例,以及它如何影响生成的 JSON 模式:
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'}, {'type': 'string'}],
'default': '12.34',
'title': 'A',
}
},
'title': 'Model',
'type': 'object',
}
"""
print(Model.model_json_schema(mode='serialization'))
"""
{
'properties': {'a': {'default': '12.34', 'title': 'A', 'type': 'string'}},
'title': 'Model',
'type': 'object',
}
"""
自定义 JSON 模式¶
通过以下方式可以在字段级别和模型级别自定义生成的 JSON 模式:
-
使用
Field
构造函数进行字段级定制 -
使用
model_config
进行模型级定制
在字段和模型级别,您都可以使用 json_schema_extra
选项向 JSON 模式添加额外信息。下面的“使用 json_schema_extra
”部分提供了有关此选项的更多详细信息。
对于自定义类型,Pydantic 提供了其他用于自定义 JSON 模式生成的工具:
字段级定制
可选地,可以使用 Field
函数来提供有关字段和验证的额外信息。
一些字段参数专门用于自定义生成的 JSON 模式:
title
:字段标题。description
:该字段的描述。examples
:该字段的示例。json_schema_extra
:要添加到字段的其他 JSON 模式属性。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=['marcelo@mail.com'])
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))
"""
{
"properties": {
"age": {
"description": "Age of the user",
"title": "Age",
"type": "integer"
},
"email": {
"examples": [
"marcelo@mail.com"
],
"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 发现没有被强制执行的约束,将引发错误。如果您想强制约束出现在模式中,即使在解析时没有检查到它,您可以使用带有原始模式属性名称的可变参数来 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',
}
"""
你也可以通过 Field
构造函数通过 [ typing.Annotated
][] 指定 JSON 模式修改:
import json
from uuid import uuid4
from typing_extensions import Annotated
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))
"""
{
"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 模式生成。具体来说,以下配置选项是相关的:
- [项目 0][pydantic.config.ConfigDict.标题]
使用 json_schema_extra
¶
json_schema_extra
选项可用于向 JSON 模式添加额外信息,既可以在字段级别,也可以在模型级别。可以将 dict
或 Callable
传递给 json_schema_extra
。
使用 json_schema_extra
和 dict
你可以将一个 dict
传递给 json_schema_extra
,以向 JSON 模式添加额外信息:
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))
"""
{
"examples": [
{
"a": "Foo"
}
],
"properties": {
"a": {
"title": "A",
"type": "string"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
"""
使用 json_schema_extra
和 Callable
你可以将一个 Callable
传递给 json_schema_extra
,通过一个函数来修改 JSON 模式:
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))
"""
{
"properties": {
"a": {
"title": "A",
"type": "integer"
}
},
"title": "Model",
"type": "object"
}
"""
合并 json_schema_extra
¶
从版本 2.9 开始,Pydantic 会合并来自已注释类型的 json_schema_extra
字典。这种模式提供了一种更具添加性的合并方式,而不是之前的覆盖行为。对于在多个类型之间重用 json 模式额外信息的情况,这可能非常有帮助。
我们主要将此更改视为错误修复,因为它解决了 BaseModel
和 TypeAdapter
实例之间 json_schema_extra
合并行为的意外差异——更多详细信息请参见此问题。
import json
from typing_extensions import Annotated, 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"
}
"""
如果你希望最后一个 json_schema_extra
规范覆盖前面的规范,你可以使用 callable
进行更重大的更改,包括添加或删除键,或修改值。如果你希望模仿 Pydantic v2.8 及更早版本中存在的 json_schema_extra
覆盖的行为,可以使用此模式:
import json
from typing_extensions import Annotated, TypeAlias
from pydantic import Field, TypeAdapter
from pydantic.json_schema import JsonDict
ExternalType: TypeAlias = Annotated[
int, Field(..., json_schema_extra={'key1': 'value1', 'key2': 'value2'})
]
def finalize_schema(s: JsonDict) -> None:
s.pop('key1')
s['key2'] = s['key2'] + '-final'
s['key3'] = 'value3-final'
ta = TypeAdapter(
Annotated[ExternalType, Field(..., json_schema_extra=finalize_schema)]
)
print(json.dumps(ta.json_schema(), indent=2))
"""
{
"key2": "value2-final",
"key3": "value3-final",
"type": "integer"
}
"""
WithJsonSchema
annotation¶
WithJsonSchema
注释
API Documentation
提示
使用 WithJsonSchema
] 优于为自定义类型实现 __get_pydantic_json_schema__
,因为它更简单且错误更少。
WithJsonSchema
注释可用于覆盖给定类型生成的(基本)JSON 模式,而无需在类型本身实现 __get_pydantic_core_schema__
或 __get_pydantic_json_schema__
。
这为设置 JSON 模式提供了一种方法,对于否则会在生成 JSON 模式时引发错误的类型,例如 Callable
,或具有 is-instance
核心模式的类型。
例如,在以下示例中使用 PlainValidator
会在生成 JSON 模式时引发错误,因为 PlainValidator
是一个 Callable
。但是,通过使用 WithJsonSchema
注释,我们可以覆盖自定义 MyInt
类型生成的 JSON 模式:
import json
from typing_extensions import Annotated
from pydantic import BaseModel, PlainValidator, WithJsonSchema
MyInt = Annotated[
int,
PlainValidator(lambda v: int(v) + 1),
WithJsonSchema({'type': 'integer', 'examples': [1, 0, -1]}),
]
class Model(BaseModel):
a: MyInt
print(Model(a='1').a)
#> 2
print(json.dumps(Model.model_json_schema(), indent=2))
"""
{
"properties": {
"a": {
"examples": [
1,
0,
-1
],
"title": "A",
"type": "integer"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
"""
注意
正如本问题中所讨论的,未来,Pydantic 很可能会为 PlainValidator
等类型添加内置的 JSON 模式生成支持,但 WithJsonSchema
注释对于其他自定义类型仍然有用。
SkipJsonSchema
annotation¶
SkipJsonSchema
注释
API Documentation
SkipJsonSchema
注释可用于从生成的 JSON 模式中跳过包含的字段(或字段规范的一部分)。有关更多详细信息,请参阅 API 文档。
实施 __get_pydantic_core_schema__
¶
自定义类型(用作 field_name: TheType
或 field_name: Annotated[TheType, ...]
)以及 Annotated
元数据(用作 field_name: Annotated[int, SomeMetadata]
)可以通过实现 __get_pydantic_core_schema__
来修改或覆盖生成的架构。此方法接收两个位置参数:
-
与该类型对应的类型注释(因此,在
TheType[T][int]
的情况下,它将是TheType[int]
)。 -
调用
__get_pydantic_core_schema__
的下一个实现者的处理程序/回调。
处理程序系统的工作方式与 mode='wrap'
验证器类似。在这种情况下,输入是类型,输出是 core_schema
。
以下是一个自定义类型的示例,该类型覆盖了生成的 core_schema
:
from dataclasses import dataclass
from typing import Any, Dict, List, Type
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
生成模式,如果在其 __get_pydantic_core_schema__
方法中调用 handler(source)
,则会得到一个 pydantic.errors.PydanticSchemaGenerationError
错误。对于大多数自定义类型来说都是这种情况,因此几乎从不希望为自定义类型调用 handler
。
Annotated
元数据的处理过程大致相同,只是通常可以调用 handler
让 Pydantic 处理生成模式。
from dataclasses import dataclass
from typing import Any, Sequence, Type
from pydantic_core import core_schema
from typing_extensions import Annotated
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]
"""
到目前为止,我们一直在包装模式,但如果你只是想修改它或忽略它,也可以这样做。
要修改模式,首先调用处理程序,然后修改结果:
from typing import Any, Type
from pydantic_core import ValidationError, core_schema
from typing_extensions import Annotated
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]
"""
注意,即使您只是就地修改模式,也必须返回一个模式。
要完全覆盖模式,请不要调用处理程序并返回您自己的 CoreSchema
:
from typing import Any, Type
from pydantic_core import ValidationError, core_schema
from typing_extensions import Annotated
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]
"""
如上文所见,使用 BaseModel
类型注释一个字段可以用于修改或覆盖生成的 JSON 模式。但是,如果您想利用 Annotated
存储元数据,但又不想覆盖生成的 JSON 模式,则可以在元数据类上实现一个空操作版本的 __get_pydantic_core_schema__
来采用以下方法:
from typing import Type
from pydantic_core import CoreSchema
from typing_extensions import Annotated
from pydantic import BaseModel, GetCoreSchemaHandler
class Metadata(BaseModel):
foo: str = 'metadata!'
bar: int = 100
@classmethod
def __get_pydantic_core_schema__(
cls, source_type: Type[BaseModel], handler: GetCoreSchemaHandler
) -> CoreSchema:
if cls is not source_type:
return handler(source_type)
return super().__get_pydantic_core_schema__(source_type, handler)
class Model(BaseModel):
state: Annotated[int, Metadata()]
m = Model.model_validate({'state': 2})
print(repr(m))
#> Model(state=2)
print(m.model_fields)
"""
{
'state': FieldInfo(
annotation=int,
required=True,
metadata=[Metadata(foo='metadata!', bar=100)],
)
}
"""
实施 __get_pydantic_json_schema__
¶
你还可以实现 __get_pydantic_json_schema__
来修改或覆盖生成的 json 模式。修改此方法仅影响 JSON 模式——它不会影响用于验证和序列化的核心模式。
以下是修改生成的 JSON 模式的示例:
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))
"""
{
"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 typing import Type
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 模式类型¶
类型、自定义字段类型和约束(如 max_length
)按照以下优先级顺序映射到相应的规范格式(当有等效格式时):
- JSON 模式核心
- JSON 模式验证
- OpenAPI 数据类型
- 标准的
format
JSON 字段用于定义 Pydantic 扩展,以支持更复杂的string
子类型。
从 Python 或 Pydantic 到 JSON 模式的字段模式映射如下进行:
顶级模式生成¶
你还可以生成一个顶级 JSON 模式,该模式在其 $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))
"""
{
"$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"
}
"""
Customizing the JSON Schema Generation Process¶
自定义 JSON 模式生成过程
API 文档
如果需要自定义模式生成,可以使用 schema_generator
,根据应用程序的需要修改 GenerateJsonSchema
类。
可以用于生成 JSON 模式的各种方法接受一个关键字参数 schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema
,您可以将自定义子类传递给这些方法,以使用自己的方法生成 JSON 模式。
GenerateJsonSchema
实现了将类型的 pydantic-core
模式转换为 JSON 模式的功能。从设计上讲,此类将 JSON 模式生成过程分解为较小的方法,可以在子类中轻松覆盖这些方法,以修改生成 JSON 模式的“全局”方法。
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.org/draft/2020-12/schema',
}
"""
以下是一种可以用来排除模式中没有有效 JSON 模式的任何字段的方法:
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',
}
"""
在 JSON Schema 中自定义 $ref
¶
$ref
的格式可以通过调用 model_json_schema()
或 model_dump_json()
并使用 ref_template
关键字参数来更改。定义始终存储在 $defs
键下,但可以为引用指定指定的前缀。
如果需要扩展或修改 JSON 模式默认定义的位置,这将很有用。例如,对于 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,
)
)
"""
{
"$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 模式生成杂记¶
Optional
字段的 JSON 模式表明允许的值为null
。Decimal
类型在 JSON 模式(和序列化)中暴露为字符串。- 由于
namedtuple
类型在 JSON 中不存在,因此模型的 JSON 模式不会将namedtuple
保留为namedtuple
。 - 根据规范,将子模型添加到
$defs
JSON 属性中并引用。 - 具有修改的子模型(通过
Field
类),例如自定义标题、描述或默认值,会被递归包含,而不是被引用。 - 模型的
description
取自类的文档字符串或Field
类的description
参数。 - 该模式默认使用别名作为键生成,但也可以通过调用
model_json_schema()
或model_dump_json()
并使用by_alias=False
关键字参数使用模型属性名称生成。
本文总阅读量次