シリアライズ
フィールド名 (例: model.foobar
) を介してモデル属性に直接アクセスするだけでなく、モデルはさまざまな方法で変換、ダンプ、シリアル化、エクスポートできます。
!!!ヒント 「シリアライズとダンプ」 Pydantic では、「シリアライズ」と「ダンプ」という用語を同じ意味で使用します。どちらも、モデルを辞書または JSON エンコード文字列に変換するプロセスを指します。
Outside of Pydantic, the word "serialize" usually refers to converting in-memory data into a string or bytes.
However, in the context of Pydantic, there is a very close relationship between converting an object from a more
structured form — such as a Pydantic model, a dataclass, etc. — into a less structured form comprised of
Python built-ins such as dict.
While we could (and on occasion, do) distinguish between these scenarios by using the word "dump" when converting to
primitives and "serialize" when converting to string, for practical purposes, we frequently use the word "serialize"
to refer to both of these situations, even though it does not always imply conversion to a string or bytes.
model.model_dump(...)
¶
??? API「APIドキュメント」 pydantic.main.BaseModel.model_dump
これは、モデルを辞書に変換する主な方法です。サブモデルは再帰的に辞書に変換されます。
!!! note 注 サブモデルが辞書に変換される場合の 1 つの例外は、 RootModel
とそのサブクラスでは、 root
フィールド値がラップ辞書なしで直接ダンプされることです。これも再帰的に行われます。
!!! note計算フィールドを使用して、 model.model_dump(...)
出力にproperty
とcached_property
データを含めることができます。
例:
from typing import Any, List, Optional
from pydantic import BaseModel, Field, Json
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: Optional[float] = 1.1
foo: str = Field(serialization_alias='foo_alias')
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
# returns a dictionary:
print(m.model_dump())
#> {'banana': 3.14, 'foo': 'hello', 'bar': {'whatever': 123}}
print(m.model_dump(include={'foo', 'bar'}))
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(m.model_dump(exclude={'foo', 'bar'}))
#> {'banana': 3.14}
print(m.model_dump(by_alias=True))
#> {'banana': 3.14, 'foo_alias': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(foo='hello', bar={'whatever': 123}).model_dump(
exclude_unset=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(banana=1.1, foo='hello', bar={'whatever': 123}).model_dump(
exclude_defaults=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(foo='hello', bar={'whatever': 123}).model_dump(
exclude_defaults=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(banana=None, foo='hello', bar={'whatever': 123}).model_dump(
exclude_none=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
class Model(BaseModel):
x: List[Json[Any]]
print(Model(x=['{"a": 1}', '[1, 2]']).model_dump())
#> {'x': [{'a': 1}, [1, 2]]}
print(Model(x=['{"a": 1}', '[1, 2]']).model_dump(round_trip=True))
#> {'x': ['{"a":1}', '[1,2]']}
model.model_dump_json(...)
¶
??? API「APIドキュメント」 pydantic.main.BaseModel.model_dump_json
.model_dump_json()
メソッドは、 .model_dump()
によって生成された結果と同等の JSON エンコード文字列にモデルを直接シリアル化します。
詳細については、引数を参照してください。
!!! Pydantic は、単純なjson.dumps(foobar)
(例: datetime
、 date
、またはUUID
) と互換性のない、一般的に使用される多くの型を JSON にシリアル化できます。
from datetime import datetime
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
foo: datetime
bar: BarModel
m = FooBarModel(foo=datetime(2032, 6, 1, 12, 13, 14), bar={'whatever': 123})
print(m.model_dump_json())
#> {"foo":"2032-06-01T12:13:14","bar":{"whatever":123}}
print(m.model_dump_json(indent=2))
"""
{
"foo": "2032-06-01T12:13:14",
"bar": {
"whatever": 123
}
}
"""
dict(model)
と反復¶
Pydantic モデルは、 dict(model)
を使用して辞書に変換することもでき、また、次を使用してモデルのフィールドを反復処理することもできます。 for field_name, field_value in model:
。このアプローチでは、生のフィールド値が返されるため、サブモデルは辞書に変換されません。
例:
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
print(dict(m))
#> {'banana': 3.14, 'foo': 'hello', 'bar': BarModel(whatever=123)}
for name, value in m:
print(f'{name}: {value}')
#> banana: 3.14
#> foo: hello
#> bar: whatever=123
RootModel
キー'root'
を持つ辞書に変換される_こと_にも注意してください。
カスタムシリアライザー¶
Pydantic は、モデルを辞書または JSON にシリアル化する方法をカスタマイズするために、いくつかの [関数型シリアライザー][pydantic.functionerializers] を提供します。
- [
@field_serializer
][pydantic.function_serializers.field_serializer] - [
@model_serializer
][pydantic.function_serializers.model_serializer] - [
PlainSerializer
][pydantic.function_serializers.PlainSerializer] - [
WrapSerializer
][pydantic.function_serializers.WrapSerializer]
シリアル化は、フィールドでは [@field_serializer
][pydantic.function_serializers.field_serializer] デコレーターを使用してカスタマイズでき、モデルでは [@model_serializer
][pydantic.function_serializers.model_serializer] デコレーターを使用してカスタマイズできます。
from datetime import datetime, timedelta, timezone
from typing import Any, Dict
from pydantic import BaseModel, ConfigDict, field_serializer, model_serializer
class WithCustomEncoders(BaseModel):
model_config = ConfigDict(ser_json_timedelta='iso8601')
dt: datetime
diff: timedelta
@field_serializer('dt')
def serialize_dt(self, dt: datetime, _info):
return dt.timestamp()
m = WithCustomEncoders(
dt=datetime(2032, 6, 1, tzinfo=timezone.utc), diff=timedelta(hours=100)
)
print(m.model_dump_json())
#> {"dt":1969660800.0,"diff":"P4DT4H"}
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> Dict[str, Any]:
return {'x': f'serialized {self.x}'}
print(Model(x='test value').model_dump_json())
#> {"x":"serialized test value"}
!!! note 特別な値 '*' を [@field_serializer
][pydantic.function_serializers.field_serializer] デコレーターに渡すことで、すべてのフィールドで単一のシリアライザーを呼び出すこともできます。
さらに、[PlainSerializer
][pydantic.functionerializers.PlainSerializer] と [WrapSerializer
][pydantic.function_serializers.WrapSerializer] を使用すると、関数を使用してシリアル化の出力を変更できます。
どちらのシリアライザーも、次のようなオプションの引数を受け入れます。
return_type
関数の戻り値の型を指定します。省略した場合は、型アノテーションから推測されます。when_used
このシリアライザーをいつ使用するかを指定します。 「always」、「unless-none」、「json」、および「json-unless-none」の値を持つ文字列を受け入れます。デフォルトは「常に」です。
PlainSerializer
単純な関数を使用してシリアル化の出力を変更します。
from typing_extensions import Annotated
from pydantic import BaseModel
from pydantic.functional_serializers import PlainSerializer
FancyInt = Annotated[
int, PlainSerializer(lambda x: f'{x:,}', return_type=str, when_used='json')
]
class MyModel(BaseModel):
x: FancyInt
print(MyModel(x=1234).model_dump())
#> {'x': 1234}
print(MyModel(x=1234).model_dump(mode='json'))
#> {'x': '1,234'}
WrapSerializer
標準のシリアル化ロジックを適用するハンドラー関数とともに生の入力を受け取り、結果の値をシリアル化の最終出力として返す前に変更できます。
from typing import Any
from typing_extensions import Annotated
from pydantic import BaseModel, SerializerFunctionWrapHandler
from pydantic.functional_serializers import WrapSerializer
def ser_wrap(v: Any, nxt: SerializerFunctionWrapHandler) -> str:
return f'{nxt(v + 1):,}'
FancyInt = Annotated[int, WrapSerializer(ser_wrap, when_used='json')]
class MyModel(BaseModel):
x: FancyInt
print(MyModel(x=1234).model_dump())
#> {'x': 1234}
print(MyModel(x=1234).model_dump(mode='json'))
#> {'x': '1,235'}
モデルをダンプするときに戻り値の型をオーバーライドする¶
.model_dump()
の戻り値は通常、 dict[str, Any]
として記述できますが、 @model_serializer
を使用すると、実際にこのシグネチャに一致しない値を返すようにすることができます。
from pydantic import BaseModel, model_serializer
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> str:
return self.x
print(Model(x='not a dict').model_dump())
#> not a dict
これを行いながら、このメソッドの適切な型チェックを取得したい場合は、 if TYPE_CHECKING:
ブロックで.model_dump()
オーバーライドできます。
from typing import TYPE_CHECKING, Any
from typing_extensions import Literal
from pydantic import BaseModel, model_serializer
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> str:
return self.x
if TYPE_CHECKING:
# Ensure type checkers see the correct return type
def model_dump(
self,
*,
mode: Literal['json', 'python'] | str = 'python',
include: Any = None,
exclude: Any = None,
by_alias: bool = False,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
warnings: bool = True,
) -> str: ...
このトリックは、実際にはまさにこの目的のためにRootModel
で使用されています。
サブクラスのシリアル化¶
標準型のサブクラス¶
標準タイプのサブクラスは、スーパークラスと同様に自動的にダンプされます。
from datetime import date, timedelta
from typing import Any, Type
from pydantic_core import core_schema
from pydantic import BaseModel, GetCoreSchemaHandler
class DayThisYear(date):
"""
Contrived example of a special type of date that
takes an int and interprets it as a day in the current year
"""
@classmethod
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.no_info_after_validator_function(
cls.validate,
core_schema.int_schema(),
serialization=core_schema.format_ser_schema('%Y-%m-%d'),
)
@classmethod
def validate(cls, v: int):
return date(2023, 1, 1) + timedelta(days=v)
class FooModel(BaseModel):
date: DayThisYear
m = FooModel(date=300)
print(m.model_dump_json())
#> {"date":"2023-10-28"}
BaseModel
、データクラス、 TypedDict
のフィールドのサブクラス インスタンス¶
注釈自体が構造体のような型であるフィールド ( BaseModel
サブクラス、データクラスなど) を使用する場合、デフォルトの動作では、属性値がサブクラスであっても、あたかも注釈付き型のインスタンスであるかのように属性値をシリアル化します。より具体的には、_注釈付きの_型のフィールドのみがダンプされたオブジェクトに含まれます。
from pydantic import BaseModel
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user: User
user = UserLogin(name='pydantic', password='hunter2')
m = OuterModel(user=user)
print(m)
#> user=UserLogin(name='pydantic', password='hunter2')
print(m.model_dump()) # note: the password field is not included
#> {'user': {'name': 'pydantic'}}
!!!警告 "移行警告" この動作は、モデルを dict に再帰的にダンプするときに常にすべての (サブクラス) フィールドを含める Pydantic V1 での動作とは異なります。この動作変更の背後にある動機は、オブジェクトのインスタンス化時にサブクラスが渡された場合でも、シリアル化時にどのフィールドが含まれる可能性があるかを正確に把握できるようにすることです。これは特に、シークレットなどの機密情報をサブクラスのフィールドとして追加するときに予期せぬ事態を防ぐのに役立ちます。
アヒルタイピングで連載中🦆¶
!!!質問「ダックタイピングによるシリアル化とは何ですか?」
Duck-typing serialization is the behavior of serializing an object based on the fields present in the object itself,
rather than the fields present in the schema of the object. This means that when an object is serialized, fields present in
a subclass, but not in the original schema, will be included in the serialized output.
This behavior was the default in Pydantic V1, but was changed in V2 to help ensure that you know precisely which
fields would be included when serializing, even if subclasses get passed when instantiating the object. This helps
prevent security risks when serializing subclasses with sensitive information, for example.
v1 スタイルのダックタイピングのシリアル化動作が必要な場合は、ランタイム設定を使用するか、個々の型に注釈を付けることができます。
- フィールド/型レベル:
SerializeAsAny
注釈を使用します - ランタイム レベル:
model_dump()
またはmodel_dump_json()
を呼び出すときに、serialize_as_any
フラグを使用します。
これらのオプションについては、以下で詳しく説明します。
SerializeAsAny
注釈:¶
ダックタイピングのシリアル化動作が必要な場合は、型のSerializeAsAny
アノテーションを使用して実行できます。
from pydantic import BaseModel, SerializeAsAny
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
as_any: SerializeAsAny[User]
as_user: User
user = UserLogin(name='pydantic', password='password')
print(OuterModel(as_any=user, as_user=user).model_dump())
"""
{
'as_any': {'name': 'pydantic', 'password': 'password'},
'as_user': {'name': 'pydantic'},
}
"""
フィールドにSerializeAsAny[<SomeType>]
の注釈が付けられている場合、検証動作は<SomeType>
の注釈が付けられている場合と同じになり、 mypy のような型チェッカーは属性も適切な型を持つものとして扱います。ただし、シリアル化する場合、フィールドの型ヒントがAny
あるかのように、フィールドはシリアル化されます。これが名前の由来です。
serialize_as_any
ランタイム設定¶
serialize_as_any
ランタイム設定を使用すると、ダック タイプのシリアル化動作の有無にかかわらず、モデル データをシリアル化できます。 serialize_as_any
、キーワード引数としてBaseModel
およびRootModel
のmodel_dump()
およびmodel_dump_json
メソッドに渡すことができます。 TypeAdapter
のdump_python()
メソッドとdump_json()
メソッドにキーワード引数として渡すこともできます。
serialize_as_any
がTrue
に設定されている場合、モデルはアヒル型のシリアル化動作を使用してシリアル化されます。これは、モデルがスキーマを無視し、代わりにオブジェクト自体にどのようにシリアル化するかを尋ねることを意味します。これは特に、モデルのサブクラスがシリアル化されると、サブクラスには存在するが元のスキーマには存在しないフィールドが含まれることを意味します。
serialize_as_any
がFalse
(デフォルト) に設定されている場合、モデルはスキーマを使用してシリアル化されます。つまり、サブクラスには存在するが元のスキーマには存在しないフィールドは無視されます。
!!!質問「なぜこのフラグが役立つのですか?」場合によっては、サブクラスにどのようなフィールドが追加されたとしても、シリアル化されたオブジェクトには元の型定義にリストされているフィールドのみが含まれるようにしたいことがあります。これは、シリアル化された出力に誤って含めたくないサブクラスに、 password: str
フィールドのようなものを追加する場合に便利です。
例えば:
from pydantic import BaseModel
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user1: User
user2: User
user = UserLogin(name='pydantic', password='password')
outer_model = OuterModel(user1=user, user2=user)
print(outer_model.model_dump(serialize_as_any=True)) # (1)!
"""
{
'user1': {'name': 'pydantic', 'password': 'password'},
'user2': {'name': 'pydantic', 'password': 'password'},
}
"""
print(outer_model.model_dump(serialize_as_any=False)) # (2)!
#> {'user1': {'name': 'pydantic'}, 'user2': {'name': 'pydantic'}}
serialize_as_any
True
に設定すると、結果は V1 の結果と一致します。serialize_as_any
False
(V2 のデフォルト) に設定すると、基本クラスではなくサブクラスに存在するフィールドはシリアル化に含まれません。
この設定は、ネストされたパターンや再帰的なパターンにも同様に有効です。例えば:
from typing import List
from pydantic import BaseModel
class User(BaseModel):
name: str
friends: List['User']
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user: User
user = UserLogin(
name='samuel',
password='pydantic-pw',
friends=[UserLogin(name='sebastian', password='fastapi-pw', friends=[])],
)
print(OuterModel(user=user).model_dump(serialize_as_any=True)) # (1)!
"""
{
'user': {
'name': 'samuel',
'friends': [
{'name': 'sebastian', 'friends': [], 'password': 'fastapi-pw'}
],
'password': 'pydantic-pw',
}
}
"""
print(OuterModel(user=user).model_dump(serialize_as_any=False)) # (2)!
"""
{'user': {'name': 'samuel', 'friends': [{'name': 'sebastian', 'friends': []}]}}
"""
- ネストされた
User
モデル インスタンスであっても、User
サブクラスに固有のフィールドとともにダンプされます。 - ネストされた
User
モデル インスタンスであっても、User
サブクラスに固有のフィールドなしでダンプされます。
!!! note 注: serialize_as_any
ランタイム フラグの動作は、 SerializeAsAny
アノテーションの動作とほぼ同じです。解決に向けて取り組んでいる微妙な違いがいくつかありますが、ほとんどの場合、両方で同じ動作が期待できます。この現在進行中の問題の相違点の詳細を参照してください
serialize_as_any
デフォルトをオーバーライドする (False)¶
serialize_as_any
のデフォルト設定をオーバーライドするには、 model_dump()
およびmodel_dump_json()
へのserialize_as_any
引数のデフォルトをオーバーライドするBaseModel
のサブクラスを構成し、それを任意のモデルの基本クラス ( pydantic.BaseModel
の代わりに) として使用します。このデフォルトの動作を希望します。
たとえば、デフォルトでダックタイピング シリアル化を使用する場合は、次のようにすることができます。
from typing import Any, Dict
from pydantic import BaseModel, SecretStr
class MyBaseModel(BaseModel):
def model_dump(self, **kwargs) -> Dict[str, Any]:
return super().model_dump(serialize_as_any=True, **kwargs)
def model_dump_json(self, **kwargs) -> str:
return super().model_dump_json(serialize_as_any=True, **kwargs)
class User(MyBaseModel):
name: str
class UserInfo(User):
password: SecretStr
class OuterModel(MyBaseModel):
user: User
u = OuterModel(user=UserInfo(name='John', password='secret_pw'))
print(u.model_dump_json()) # (1)!
#> {"user":{"name":"John","password":"**********"}}
- デフォルトでは、
model_dump_json
ダックタイピングのシリアル化動作を使用します。これは、password
フィールドが出力に含まれることを意味します。
pickle.dumps(model)
¶
Pydantic モデルは、効率的な酸洗いと酸洗い解除をサポートします。
import pickle
from pydantic import BaseModel
class FooBarModel(BaseModel):
a: str
b: int
m = FooBarModel(a='hello', b=123)
print(m)
#> a='hello' b=123
data = pickle.dumps(m)
print(data[:20])
#> b'\x80\x04\x95\x95\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main_'
m2 = pickle.loads(data)
print(m2)
#> a='hello' b=123
高度な包含および除外¶
model_dump
とmodel_dump_json
メソッドは、セットまたは辞書のいずれかであるinclude
およびexclude
引数をサポートします。これにより、エクスポートするフィールドをネストして選択できるようになります。
from pydantic import BaseModel, SecretStr
class User(BaseModel):
id: int
username: str
password: SecretStr
class Transaction(BaseModel):
id: str
user: User
value: int
t = Transaction(
id='1234567890',
user=User(id=42, username='JohnDoe', password='hashedpassword'),
value=9876543210,
)
# using a set:
print(t.model_dump(exclude={'user', 'value'}))
#> {'id': '1234567890'}
# using a dict:
print(t.model_dump(exclude={'user': {'username', 'password'}, 'value': True}))
#> {'id': '1234567890', 'user': {'id': 42}}
print(t.model_dump(include={'id': True, 'user': {'id'}}))
#> {'id': '1234567890', 'user': {'id': 42}}
True
、キーをセットに含めるかのように、キー全体を除外または含めることを示します。これは任意の深さレベルで実行できます。
サブモデルまたはディクショナリのリストまたはタプルにフィールドを含めたり除外したりする場合は、特別な注意が必要です。このシナリオでは、 model_dump
および関連メソッドは、要素ごとの包含または除外のために整数キーを期待します。リストまたはタプルのすべてのメンバーからフィールドを除外するには、次に示すように、辞書キー'__all__'
を使用できます。
import datetime
from typing import List
from pydantic import BaseModel, SecretStr
class Country(BaseModel):
name: str
phone_code: int
class Address(BaseModel):
post_code: int
country: Country
class CardDetails(BaseModel):
number: SecretStr
expires: datetime.date
class Hobby(BaseModel):
name: str
info: str
class User(BaseModel):
first_name: str
second_name: str
address: Address
card_details: CardDetails
hobbies: List[Hobby]
user = User(
first_name='John',
second_name='Doe',
address=Address(
post_code=123456, country=Country(name='USA', phone_code=1)
),
card_details=CardDetails(
number='4212934504460000', expires=datetime.date(2020, 5, 1)
),
hobbies=[
Hobby(name='Programming', info='Writing code and stuff'),
Hobby(name='Gaming', info='Hell Yeah!!!'),
],
)
exclude_keys = {
'second_name': True,
'address': {'post_code': True, 'country': {'phone_code'}},
'card_details': True,
# You can exclude fields from specific members of a tuple/list by index:
'hobbies': {-1: {'info'}},
}
include_keys = {
'first_name': True,
'address': {'country': {'name'}},
'hobbies': {0: True, -1: {'name'}},
}
# would be the same as user.model_dump(exclude=exclude_keys) in this case:
print(user.model_dump(include=include_keys))
"""
{
'first_name': 'John',
'address': {'country': {'name': 'USA'}},
'hobbies': [
{'name': 'Programming', 'info': 'Writing code and stuff'},
{'name': 'Gaming'},
],
}
"""
# To exclude a field from all members of a nested list or tuple, use "__all__":
print(user.model_dump(exclude={'hobbies': {'__all__': {'info'}}}))
"""
{
'first_name': 'John',
'second_name': 'Doe',
'address': {
'post_code': 123456,
'country': {'name': 'USA', 'phone_code': 1},
},
'card_details': {
'number': SecretStr('**********'),
'expires': datetime.date(2020, 5, 1),
},
'hobbies': [{'name': 'Programming'}, {'name': 'Gaming'}],
}
"""
同じことが、 model_dump_json
メソッドにも当てはまります。
モデルレベルおよびフィールドレベルでの包含および除外¶
model_dump
とmodel_dump_json
メソッドに渡される明示的な引数exclude
とinclude
に加えて、 exclude: bool
引数をField
コンストラクターに直接渡すこともできます。
フィールド コンストラクターのexclude
設定 ( Field(..., exclude=True)
) はmodel_dump
およびmodel_dump_json
のexclude
/ include
よりも優先されます。
from pydantic import BaseModel, Field, SecretStr
class User(BaseModel):
id: int
username: str
password: SecretStr = Field(..., exclude=True)
class Transaction(BaseModel):
id: str
value: int = Field(exclude=True)
t = Transaction(
id='1234567890',
value=9876543210,
)
print(t.model_dump())
#> {'id': '1234567890'}
print(t.model_dump(include={'id': True, 'value': True})) # (1)!
#> {'id': '1234567890'}
value
Field
で除外されているため、出力から除外されます。
ただし、フィールド コンストラクターでのexclude
設定 ( Field(..., exclude=True)
) は、 model_dump
およびmodel_dump_json
のexclude_unset
、 exclude_none
、およびexclude_default
パラメーターよりも優先されません。
from typing import Optional
from pydantic import BaseModel, Field
class Person(BaseModel):
name: str
age: Optional[int] = Field(None, exclude=False)
person = Person(name='Jeremy')
print(person.model_dump())
#> {'name': 'Jeremy', 'age': None}
print(person.model_dump(exclude_none=True)) # (1)!
#> {'name': 'Jeremy'}
print(person.model_dump(exclude_unset=True)) # (2)!
#> {'name': 'Jeremy'}
print(person.model_dump(exclude_defaults=True)) # (3)!
#> {'name': 'Jeremy'}
exclude_none
がTrue
に設定されており、age
がNone
であるため、age
出力から除外されます。exclude_unset
がTrue
に設定されており、age
が Person コンストラクターに設定されていなかったため、age
出力から除外されました。exclude_defaults
がTrue
に設定されており、age
デフォルト値のNone
使用するため、age
出力から除外されます。
シリアル化コンテキスト¶
コンテキスト オブジェクトをシリアル化メソッドに渡すことができます。シリアル化メソッドには、 info
引数から装飾されたシリアライザー関数にアクセスできます。これは、実行時にシリアル化動作を動的に更新する必要がある場合に便利です。たとえば、動的に制御可能な一連の許可された値に応じてフィールドをダンプしたい場合は、許可された値をコンテキストで渡すことで実行できます。
from pydantic import BaseModel, SerializationInfo, field_serializer
class Model(BaseModel):
text: str
@field_serializer('text')
def remove_stopwords(self, v: str, info: SerializationInfo):
context = info.context
if context:
stopwords = context.get('stopwords', set())
v = ' '.join(w for w in v.split() if w.lower() not in stopwords)
return v
model = Model.model_construct(**{'text': 'This is an example document'})
print(model.model_dump()) # no context
#> {'text': 'This is an example document'}
print(model.model_dump(context={'stopwords': ['this', 'is', 'an']}))
#> {'text': 'example document'}
print(model.model_dump(context={'stopwords': ['document']}))
#> {'text': 'This is an example'}
同様に、検証にコンテキストを使用できます。
model_copy(...)
¶
??? API「APIドキュメント」 pydantic.main.BaseModel.model_copy
model_copy()
と、(オプションの更新を使用して) モデルを複製できます。これは、フリーズされたモデルを操作する場合に特に便利です。
例:
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
print(m.model_copy(update={'banana': 0}))
#> banana=0 foo='hello' bar=BarModel(whatever=123)
print(id(m.bar) == id(m.model_copy().bar))
#> True
# normal copy gives the same object reference for bar
print(id(m.bar) == id(m.model_copy(deep=True).bar))
#> False
# deep copy gives a new object reference for `bar`
本文总阅读量次