JSON Schema
??? API「APIドキュメント」 pydantic.json_schema
Pydantic を使用すると、モデルから JSON スキーマを自動的に作成およびカスタマイズできます。生成された JSON スキーマは次の仕様に準拠しています。
JSONスキーマの生成¶
JSON スキーマを生成するには、次の関数を使用します。
BaseModel.model_json_schema
は、モデルのスキーマの jsonable dict を返します。TypeAdapter.json_schema
は、適応された型のスキーマの jsonable dict を返します。
!!! note これらのメソッドは、それぞれモデルまたは適応型のインスタンスをシリアル化する BaseModel.model_dump_json
および TypeAdapter.dump_json
と混同しないでください。 。これらのメソッドは JSON 文字列を返します。比較すると、BaseModel.model_json_schema
と TypeAdapter.json_schema
は、それぞれモデルまたは適応型の JSON スキーマを表す jsonable dict を返します。
!!!注「JSON スキーマの "jsonable" の性質について」 model_json_schema
の結果の "jsonable" の性質に関して、呼び出し json.dumps(m.model_json_schema())
一部のBaseModel
では、 m
有効な JSON 文字列を返します。同様に、TypeAdapter.json_schema
の場合は、 json.dumps(TypeAdapter(<some_type>).json_schema())
有効な JSON 文字列を返します。
!!!ヒント Pydantic は次の両方のサポートを提供します。
1. [Customizing JSON Schema](#customizing-json-schema)
2. [Customizing the JSON Schema Generation Process](#customizing-the-json-schema-generation-process)
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"
}
"""
```
1. This produces a "jsonable" dict of `MainModel`'s schema.
2. Calling `json.dumps` on the schema dict produces a JSON string.
The [`TypeAdapter`][pydantic.type_adapter.TypeAdapter] class lets you create an object with methods for validating, serializing,
and producing JSON schemas for arbitrary types. This serves as a complete replacement for `schema_of` in
Pydantic V1 (which is now deprecated).
Here's an example of generating JSON schema from a [`TypeAdapter`][pydantic.type_adapter.TypeAdapter]:
```py
from typing import List
from pydantic import TypeAdapter
adapter = TypeAdapter(List[int])
print(adapter.json_schema())
#> {'items': {'type': 'integer'}, 'type': 'array'}
```
You can also generate JSON schemas for combinations of [`BaseModel`s][pydantic.main.BaseModel]
and [`TypeAdapter`s][pydantic.type_adapter.TypeAdapter], as shown in this example:
```py
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 スキーマ生成をカスタマイズするための他のツールを提供します。
WithJsonSchema
アノテーションSkipJsonSchema
アノテーション__get_pydantic_core_schema__
の実装__get_pydantic_json_schema__
の実装
フィールドレベルのカスタマイズ¶
オプションで、 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',
}
"""
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))
"""
{
"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"
}
"""
モデルレベルのカスタマイズ¶
model config を使用して、モデルの JSON スキーマ生成をカスタマイズすることもできます。具体的には、次の構成オプションが関連します。
title
json_schema_extra
schema_generator
json_schema_mode_override
field_title_generator
model_title_generator
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"
}
"""
Callable
でのjson_schema_extra
の使用¶
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
マージ¶
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
アノテーション¶
??? API「APIドキュメント」 pydantic.json_schema.WithJsonSchema
!!!ヒント WithJsonSchema
] の使用は、よりシンプルでエラーが発生しにくいため、カスタム型に__get_pydantic_json_schema__
を実装するよりも推奨されます。
WithJsonSchema
アノテーションを使用すると、型自体に__get_pydantic_core_schema__
または__get_pydantic_json_schema__
を実装することなく、特定の型に対して生成された (ベース) JSON スキーマをオーバーライドできます。
これにより、 Callable
などの JSON スキーマの生成時にエラーが発生する型、または is-instance
コア スキーマを持つ型に対して、JSON スキーマを設定する方法が提供されます。
たとえば、次の例で [PlainValidator
][pydantic.function_validators.PlainValidator] を使用すると、[PlainValidator
][pydantic.function_validators.PlainValidator] はCallable
であるため、JSON スキーマの生成時にエラーが発生します。ただし、 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"
}
"""
!!! noteこの問題で説明したように、将来、Pydantic は [PlainValidator
][pydantic.function_validators.PlainValidator] のような型の JSON スキーマ生成の組み込みサポートを追加する可能性がありますが、WithJsonSchema
アノテーション他のカスタム タイプにも引き続き役立ちます。
SkipJsonSchema
アノテーション¶
??? API「APIドキュメント」 pydantic.json_schema.SkipJsonSchema
SkipJsonSchema
アノテーションを使用すると、生成された JSON スキーマから包含フィールド (またはフィールド仕様の一部) をスキップできます。詳細については、API ドキュメントを参照してください。
__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と同じように機能します。この場合、入力は type で、出力は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__
の 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)],
)
}
"""
__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 フィールドは、より複雑なstring
サブタイプの Pydantic 拡張機能を定義するために使用されます。
Python または Pydantic から JSON スキーマへのフィールド スキーマ マッピングは次のように行われます。
トップレベルのスキーマの生成¶
モデルと関連するリストのみを含むトップレベルの JSON スキーマを生成することもできます。 ` $defs` 内のサブモデル: ```py Output="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 クラス 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": { "バー": { "プロパティ": { "c": { "タイトル": "C", "型": "整数" } }, "必須": [ 「c」 ]、 "title": "バー", "タイプ": "オブジェクト" }, 「フー」: { "プロパティ": { "a": { 「デフォルト」: null、 "タイトル": "A", "タイプ": "文字列" } }, "タイトル": "フー", "タイプ": "オブジェクト" }, "モデル": { "プロパティ": { "b": { 」 $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": { "$ デフ/フー」 } }, "必須": [ 「b」 ]、 "タイトル": "モデル", "タイプ": "オブジェクト" } }, "title": "私のスキーマ" } 「」
## Customizing the JSON Schema Generation Process
??? api "API Documentation"
[`pydantic.json_schema`][pydantic.json_schema.GenerateJsonSchema]<br>
If you need custom schema generation, you can use a `schema_generator`, modifying the
[`GenerateJsonSchema`][pydantic.json_schema.GenerateJsonSchema] class as necessary for your application.
The various methods that can be used to produce JSON schema accept a keyword argument `schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema`, and you can pass your custom subclass to these methods in order to use your own approach to generating JSON schema.
`GenerateJsonSchema` implements the translation of a type's `pydantic-core` schema into a JSON schema.
By design, this class breaks the JSON schema generation process into smaller methods that can be easily overridden in
subclasses to modify the "global" approach to generating JSON schema.
```
py 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',
}
"""
カスタマイズする $ref`s in JSON Schema The format of `$ref
model_json_schema()
を呼び出すことで変更できます。¶
または model_dump_json()
をref_template
キーワード引数とともに使用します。定義は常にキーの下に保存されます。 $defs`, but a specified prefix can be used for the references. This is useful if you need to extend or modify the JSON schema default definitions location. For example, with OpenAPI: ```py output="json" 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" } """ ``` ## Miscellaneous Notes on JSON Schema Generation * The JSON schema for `Optional` fields indicates that the value `null` is allowed. * The `Decimal` type is exposed in JSON schema (and serialized) as a string. * Since the `namedtuple` type doesn't exist in JSON, a model's JSON schema does not preserve `namedtuple`s as `namedtuple`s. * Sub-models used are added to the `$defs
仕様に従って、JSON 属性と参照が行われます。
- カスタム タイトル、説明、デフォルト値などの変更が (
Field
クラス経由で) 行われたサブモデルは、参照されるのではなく再帰的に組み込まれます。 - モデルの
description
、クラスの docstring またはField
クラスの引数のdescription
から取得されます。 - スキーマはデフォルトでエイリアスをキーとして使用して生成されますが、代わりに
model_json_schema()
またはmodel_dump_json()
を呼び出すことでモデル プロパティ名を使用して生成できます。 model_dump_json] をby_alias=False
キーワード引数とともに使用します。