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'}
次の例に示すように、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))
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スキーマ生成をカスタマイズするための他のツールを提供しています。
WithJsonSchema
annotationSkipJsonSchema
annotation- 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スキーマ生成をカスタマイズすることもできます。 具体的には、次の設定オプションが関連します。
title
json_schema_extra
schema_generator
json_schema_mode_override
field_title_generator
model_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
など)は、次の優先順位で対応する仕様フォーマットにマップされます(同等のものが使用可能な場合)。
- 標準の
format
JSONフィールドは、より複雑な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 $ref
s 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
として保存しません。
- 使用されるサブモデルは、仕様に従って
$defs
JSON属性に追加され、参照されます。
- カスタムタイトル、説明、デフォルト値などの変更(
Field
クラスを介して)があるサブモデルは、参照されるのではなく再帰的に含まれます。
- モデルの
description
は、クラスのdocstringまたはField
クラスへの引数description
から取得されます。
- スキーマはデフォルトでエイリアスをキーとして使用して生成されますが、代わりに
model_json_schema()
またはmodel_dump_json()
をby_alias=False
キーワード引数で呼び出すことで、モデルプロパティ名を使用して生成できます。