JSON Schema
API Documentation
Pydanticでは、モデルからのJSONスキーマの自動作成とカスタマイズが可能です。 生成されたJSONスキーマは、次の仕様に準拠しています。
Generating JSON Schema¶
JSONスキーマを生成するには、次の関数を使用します。
BaseModel.model_json_schemaは、モデルのスキーマのJSON可能なdictを返します。TypeAdapter.json_schemaは、適応された型のスキーマのjson可能なdictを返します。
Note
これらのメソッドをBaseModel.model_dump_jsonおよびTypeAdapter.dump_jsonと混同しないようにしてください。これらのメソッドは、それぞれモデルまたは適応型のインスタンスを直列化します。
これらのメソッドはJSON文字列を返します。これに対して、BaseModel.model_json_schemaとTypeAdapter.json_schemaは、それぞれモデルまたは適応型のJSONスキーマを表すJSON可能なdictを返します。
on the "jsonable" nature of JSON schema
model_json_schemaの結果の"json可能"な性質に関しては、いくつかのBaseModel``mでjson.dumps(m.model_json_schema())を呼び出すと有効なJSON文字列が返されます。同様に、TypeAdapter.json_schemaでは、json.dumps(TypeAdapter(<some_type>).json_schema())を呼び出すと有効なJSON文字列が返されます。
Tip
Pydanticは以下の両方をサポートしています。
一般的に、最初のアプローチはスコープがより狭く、より特定のケースやタイプに合わせてJSONスキーマをカスタマイズできます。2番目のアプローチはスコープがより広く、JSONスキーマ生成プロセス全体をカスタマイズできます。どちらのアプローチでも同じ効果を得ることができますが、ユースケースによっては、一方のアプローチが他方よりも単純なソリューションを提供する場合があります。
以下に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)!
JSON output:
{
"$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のスキーマの"json可能な"dictを生成します。 - スキーマ辞書で
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'}
次の例に示すように、BaseModelsとTypeAdaptersの組み合わせに対して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))
JSON output:
{
"$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"
}
]
}
Configuring the JsonSchemaMode¶
model_json_schemaおよびTypeAdapter.json_schemaメソッドのmodeパラメータを使用して、JSONスキーマ生成のモードを指定します。デフォルトでは、モードはモデルの検証スキーマに対応するJSONスキーマを生成する'validation'に設定されています。
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',
}
"""
Customizing JSON Schema¶
生成されたJSONスキーマは、次の方法でフィールドレベルとモデルレベルの両方でカスタマイズできます。
Fieldコンストラクタを使用したField-level customization- モデルレベルのカスタマイズwith
model_config
フィールドレベルとモデルレベルの両方で、json_schema_extraオプションを使用してJSONスキーマに追加情報を追加できます。
このオプションの詳細については、以下のUsingjson_schema_extraセクションを参照してください。
カスタムタイプの場合、PydanticはJSONスキーマ生成をカスタマイズするための他のツールを提供しています。
WithJsonSchemaannotationSkipJsonSchemaannotation- Implementing
__get_pydantic_core_schema__ - Implementing
__get_pydantic_json_schema__
Field-Level Customization¶
オプションで、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))
JSON output:
{
"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"
}
Unenforced Field constraints¶
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',
}
"""
JSONスキーマの変更は、Fieldコンストラクタのtyping.Annotatedでも指定できます。
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))
JSON output:
{
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"name": {
"default": "Bar",
"maxLength": 256,
"title": "CustomName",
"type": "string"
}
},
"title": "Foo",
"type": "object"
}
Programmatic field title generation¶
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"
}
"""
Model-Level Customization¶
model configを使用して、モデルでのJSONスキーマ生成をカスタマイズすることもできます。 具体的には、次の設定オプションが関連します。
titlejson_schema_extraschema_generatorjson_schema_mode_overridefield_title_generatormodel_title_generator
Using json_schema_extra¶
json_schema_extraオプションを使用すると、Field levelまたはModel levelのいずれかで、JSONスキーマに追加情報を追加できます。
dictまたはCallableをjson_schema_extraに渡すことができます。
Using json_schema_extra with a 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))
JSON output:
{
"examples": [
{
"a": "Foo"
}
],
"properties": {
"a": {
"title": "A",
"type": "string"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
Using json_schema_extra with a 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))
JSON output:
{
"properties": {
"a": {
"title": "A",
"type": "integer"
}
},
"title": "Model",
"type": "object"
}
Merging json_schema_extra¶
v2.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¶
API Documentation
Tip
カスタム型には、__get_pydantic_json_schema__よりもWithJsonSchema]を使用する方が簡単でエラーが発生しにくくなります。
WithJsonSchemaアノテーションを使用すると、型自体に__get_pydantic_core_schema__や__get_pydantic_json_schema__を実装しなくても、指定された型に対して生成された(ベース)JSONスキーマをオーバーライドできます。
これは、CallableのようなJSONスキーマを生成するときにエラーを起こす型や、is-instanceコアスキーマを持つ型に対して、JSONスキーマを設定する方法を提供します。
たとえば、次の例でPlainValidatorを使用すると、JSONスキーマを生成するときにエラーが発生します。これは、PlainValidatorがCallableであるためです。ただし、WithJsonSchemaアノテーションを使用すると、生成されたJSONスキーマをカスタムMyInt型でオーバーライドできます。
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))
JSON output:
{
"properties": {
"a": {
"examples": [
1,
0,
-1
],
"title": "A",
"type": "integer"
}
},
"required": [
"a"
],
"title": "Model",
"type": "object"
}
Note
ここで説明されているように、将来的にPydanticはPlainValidatorのような型のJSONスキーマ生成の組み込みサポートを追加する可能性がありますが、WithJsonSchemaアノテーションは他のカスタム型にも役立ちます。
SkipJsonSchema annotation¶
API Documentation
[SkipJsonSchema][pydantic.json_schema. SkipJsonSchema]アノテーションを使用すると、生成されたJSONスキーマから包含フィールド(またはフィールドの仕様の一部)をスキップできます。詳細についてはAPIドキュメントを参照してください。
Implementing __get_pydantic_core_schema__ ¶
カスタム型(field_name:TheTypeまたはfield_name:Annotated[TheType, .]として使用)およびAnnotatedメタデータ(field_name:Annotated[int, SomeMetadata]として使用)は、__get_pydantic_core_schema__を実装することで、生成されたスキーマを変更または上書きできます。
このメソッドは、2つの位置引数を受け取ります。
- この型に対応する型注釈(
TheType[T][int]の場合はTheType[int]になります)。 __get_pydantic_core_schema__の次の実装者を呼び出すハンドラ/コールバック。
ハンドラシステムは、mode='wrap'validatorsのように動作します。
この場合、入力は型で、出力は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]
"""
Tip
スキーマをその場で変更する場合でも、スキーマを返さなければならないことに注意してください。
スキーマを完全に上書きするには、ハンドラを呼び出さず、独自の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__のno-opバージョンで次のアプローチを使用できます。
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)],
)
}
"""
Implementing __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))
JSON output:
{
"examples": [
{
"age": 25,
"name": "John Doe"
}
],
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"age": {
"title": "Age",
"type": "integer"
}
},
"required": [
"name",
"age"
],
"title": "Person",
"type": "object"
}
Using 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"
}
"""
Using 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 schema types¶
型、カスタムフィールド型、および制約(max_lengthなど)は、次の優先順位で対応する仕様フォーマットにマップされます(同等のものが使用可能な場合)。
- 標準の
formatJSONフィールドは、より複雑なstringサブタイプのPydantic拡張を定義するために使用されます。
PythonまたはPydanticからJSONスキーマへのフィールドスキーママッピングは、次のように行われます。
Top-level schema generation¶
また、$defsにモデルと関連するサブモデルのリストのみを含むトップレベルのJSONスキーマを生成することもできます。
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 output:
{
"$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¶
API Documentation
カスタムのスキーマ生成が必要な場合は、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',
}
"""
Customizing the $refs in JSON Schema¶
$refのフォーマットは、ref_templateキーワード引数を付けてmodel_json_schema()またはmodel_dump_json()を呼び出すことで変更できます。
定義は常にキー$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,
)
)
JSON output:
{
"$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"
}
Miscellaneous Notes on JSON Schema Generation¶
OptionalフィールドのJSONスキーマは、値nullが許可されていることを示しています。
Decimal型はJSONスキーマ内で文字列として公開されます(そしてシリアライズされます)。
namedtuple型はJSONには存在しないので、モデルのJSONスキーマはnamedtupleをnamedtupleとして保存しません。
- 使用されるサブモデルは、仕様に従って
$defsJSON属性に追加され、参照されます。
- カスタムタイトル、説明、デフォルト値などの変更(
Fieldクラスを介して)があるサブモデルは、参照されるのではなく再帰的に含まれます。
- モデルの
descriptionは、クラスのdocstringまたはFieldクラスへの引数descriptionから取得されます。
- スキーマはデフォルトでエイリアスをキーとして使用して生成されますが、代わりに
model_json_schema()またはmodel_dump_json()をby_alias=Falseキーワード引数で呼び出すことで、モデルプロパティ名を使用して生成できます。