Serialization
フィールド名(例えばmodel.foobar
)から直接モデル属性にアクセスする以外にも、モデルはさまざまな方法で変換、ダンプ、シリアライズ、エクスポートすることができます。
Serialize versus dump
Pydanticでは、"serialize"と"dump"という用語を同じ意味で使用しています。どちらも、モデルを辞書またはJSONでエンコードされた文字列に変換するプロセスを指します。
Pydantic以外では、"シリアライズ"という言葉は通常、メモリ内のデータを文字列やバイトに変換することを意味します。 しかし、Pydanticのコンテキストでは、オブジェクトをPydanticモデルやデータクラスなどのより構造化された形式から、dictなどのPython組み込みで構成されたより構造化されていない形式に変換することには、非常に密接な関係があります。
プリミティブへの変換時には"dump"、文字列への変換時には"serialize"という単語を使用することで、これらのシナリオを区別することができます(場合によっては区別します)が、実際には、必ずしも文字列やバイトへの変換を意味するわけではありませんが、"serialize"という単語を両方の状況を指すためによく使用します。
model.model_dump(...)
¶
API Documentation
これは、モデルを辞書に変換する主要な方法です。サブモデルは再帰的に辞書に変換されます。
Note
辞書に変換されるサブモデルの1つの例外は、RootModel
とそのサブクラスが、ラッピング辞書なしで直接ダンプされるroot
フィールド値を持つことです。これも再帰的に行われます。
Note
computed fieldsを使用して、property
およびcached_property
データをmodel.model_dump(...)
出力に含めることができます。
次に例を示します。
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 Documentation
.model_dump_json()
メソッドは、.model_dump()
で生成された結果と等価なJSONエンコードされた文字列にモデルを直接シリアライズします。
詳細については、argumentsを参照してください。
Note
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)
and iteration¶
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
_does_が'root'
キーを持つ辞書に変換されることにも注意してください。
Custom serializers¶
Pydanticには、モデルを辞書やJSONにシリアライズする方法をカスタマイズするためのfunctional serializersがいくつか用意されています。
シリアライゼーションは、@field_serializer
デコレータを使用してフィールド上で、また@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
デコレータに特別な値'*'を渡すことで、すべてのフィールドで単一のシリアライザを呼び出すこともできます。
さらに、PlainSerializer
とWrapSerializer
では、シリアライゼーションの出力を変更する関数を使うことができます。
どちらのシリアライザも、以下のようなオプションの引数を受け付けます。
return_type
は、関数の戻り値の型を指定します。省略すると、型の注釈から推測されます。
when_used
は、このシリアライザをいつ使用すべきかを指定します。'always'、'unless-none'、'json'、および'json-unless-none'の値を持つ文字列を受け入れます。デフォルトは'always'です。
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'}
Overriding the return type when dumping a model¶
.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
でまさにこの目的のために使われています。
Serializing subclasses¶
Subclasses of standard types¶
標準タイプのサブクラスは、スーパークラスと同様に自動的にダンプされます。
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"}
Subclass instances for fields of BaseModel
, dataclasses, TypedDict
¶
構造体に似た型(例えばBaseModel
のサブクラスやデータクラスなど)のアノテーションを持つフィールドを使用する場合、デフォルトの動作では、サブクラスであっても、属性値をアノテーション付き型のインスタンスであるかのようにシリアライズします。具体的には、_annotated_typeのフィールドのみがダンプされたオブジェクトに含まれます。
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'}}
Migration Warning
この動作は、モデルをディクテーションに再帰的にダンプするときに常にすべての(サブクラス)フィールドを含めるPydantic V1での動作とは異なります。 この動作変更の背後にあるモチベーションは、オブジェクトのインスタンス化時にサブクラスが渡された場合でも、シリアライズ時にどのフィールドが含まれるかを正確に把握できるようにするためです。 特に、これは、サブクラスのフィールドとして秘密などの機密情報を追加するときに、不測の事態を防ぐのに役立ちます。
Serializing with duck-typing 🦆¶
What is serialization with duck typing?
ダック型シリアライゼーションとは、オブジェクトのスキーマに存在するフィールドではなく、オブジェクト自体に存在するフィールドに基づいてオブジェクトをシリアライズする動作のことです。 つまり、オブジェクトがシリアライズされると、サブクラスに存在するが元のスキーマには存在しないフィールドが、シリアライズされた出力に含まれます。
この動作はPydantic V1ではデフォルトでしたが、V2では、オブジェクトのインスタンス化時にサブクラスが渡された場合でも、シリアライズ時にどのフィールドが含まれるかを正確に把握できるように変更されました。 これにより、たとえば機密情報を含むサブクラスをシリアライズする際のセキュリティリスクを防ぐことができます。
v1スタイルのduck-typingシリアライゼーション動作が必要な場合は、ランタイム設定を使用するか、個々の型にアノテーションを付けることができます。
- フィールド/型レベル:
SerializeAsAny
アノテーションを使用します。 - 実行時レベル:
model_dump()
またはmodel_dump_json()
を呼び出すときにserialize_as_any
フラグを使用してください。
これらのオプションについては、以下で詳しく説明します。
SerializeAsAny
annotation:¶
型指定のシリアライズ動作を省略したい場合は、型に対して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
runtime setting¶
serialize_as_any
ランタイム設定は、duck型のシリアライゼーション動作の有無にかかわらず、モデルデータをシリアライズするために使用できます。
serialize_as_any
は、BaseModel
およびRootModel
のmodel_dump()
およびmodel_dump_json
メソッドにキーワード引数として渡すことができます。また、TypeAdapter
のdump_python()
およびdump_json()
メソッドにキーワード引数として渡すこともできます。
serialize_as_any
がTrue
に設定されている場合、モデルはduck型の直列化動作を使用して直列化されます。つまり、モデルはスキーマを無視し、代わりにオブジェクト自体にどのように直列化されるべきかを尋ねます。
特に、これは、モデルサブクラスがシリアライズされるとき、サブクラスに存在するが元のスキーマには存在しないフィールドが含まれることを意味します。
serialize_as_any
がFalse
(デフォルト)に設定されている場合、モデルはスキーマを使用してシリアライズされます。つまり、サブクラスに存在するが元のスキーマには存在しないフィールドは無視されます。
Why is this flag useful?
場合によっては、サブクラスに追加されたフィールドが何であっても、直列化されたオブジェクトには元の型定義にリストされたフィールドしかないことを確認したいことがあります。
これは、シリアル化された出力に誤って含めたくない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
アノテーションの動作とほとんど同じです。
私たちが解決しようとしている微妙な違いがいくつかありますが、ほとんどの場合、両方から同じ動作が期待できます。
このの違いについてはactive issueを参照してください。
Overriding the serialize_as_any
default (False)¶
serialize_as_any
のデフォルト設定を上書きするには、model_dump()
とmodel_dump_json()
のserialize_as_any
引数のデフォルトを上書きするBaseModel
のサブクラスを設定し、このデフォルトの動作をさせたいモデルの基本クラスとして(pydantic.BaseModel
の代わりに)それを使用します。
たとえば、デフォルトでduck-typingシリアライゼーションを使用する場合は、次のようにします。
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
はduck-typingシリアライゼーション動作を使用します。つまり、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
Advanced include and exclude¶
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- and field-level include and exclude¶
model_dump
およびmodel_dump_json
メソッドに渡される明示的な引数exclude
およびinclude
に加えて、exclude:bool
引数をField
コンストラクタに直接渡すこともできます。
フィールドコンストラクタ(Field(... ,exclude=True)
)にexclude
を設定すると、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
で除外されているため、出力から除外されます。
とはいうものの、フィールドコンストラクタ(Field(...,exclude=True)
)にexclude
を設定しても、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
は出力から除外され、age
はデフォルト値のNone
を取ります。
Serialization Context¶
デコレートされたシリアライザ関数への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'}
同様に、use a context for validationすることもできます。
model_copy(...)
¶
API Documentation
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`