Pydantic v2のserializeが便利なので紹介します
pydanticがv2がリリースされた
pydanticのv2がリリースされました。
今回は私がv2になってちょっと嬉しかった機能を紹介したいと思います。
dict変換時に別処理をはさみたかった
pydantic v1はBaseModel
を使ったクラスを作成した際、
dict()で辞書変換を行うことが出来ました。
from datetime import datetime
from pydantic import BaseModel
from zoneinfo import ZoneInfo
class UserInfo(BaseModel):
name: str
age: int
dt: datetime
dt = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
user_info = UserInfo(name="hogehoge", age=20, dt=dt)
print(user_info.dict())
# dtは現在時間が表示される
# {'name': 'hogehoge', 'age': 20, 'dt': datetime.datetime(2023, 7, 15, 7, 9, 49, 735299, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))}
UserInfo
はdt
というdatetime型を所持しています。
このdtをdict変換時にdatetime -> str型への変換を行いたいパターンがしばしばありました。
その場合、dtに対して何かしらの処理を途中にはさみたいのですが
今までのpydanticでは途中に処理を入れる事が出来ませんでした。
そのため、私は以下のように対応していました。
from datetime import datetime
from typing import Any, Dict
from pydantic import BaseModel
from zoneinfo import ZoneInfo
class UserInfo(BaseModel):
name: str
age: int
dt: datetime
def to_dict(self) -> Dict[str, Any]:
"""dtをstr変換して返却
Returns:
Dict[str, Any]: 辞書型変換後のデータ
"""
parameter = self.dict()
parameter.update({"dt": self.dt.isoformat()})
return parameter
dt = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
user_info = UserInfo(name="hogehoge", age=20, dt=dt)
print(user_info.to_dict())
# {'name': 'hogehoge', 'age': 20, 'dt': '2023-07-15T07:18:47.517362+09:00'}
自前でto_dict()
を準備し、その中で変換を行う処理です。
私の中では許容範囲でしたが、もっといい方法はないかな…と思っていました。
v2で進化していた
v2ではどうなったかといいますと、だいぶ進化していました。
まず、辞書変換時に使用するのはdict()
ではなくmodel_dump()
です。
from datetime import datetime
from pydantic import BaseModel
from zoneinfo import ZoneInfo
class UserInfo(BaseModel):
name: str
age: int
dt: datetime
dt = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
user_info = UserInfo(name="hogehoge", age=20, dt=dt)
print(user_info.model_dump())
# {'name': 'hogehoge', 'age': 20, 'dt': datetime.datetime(2023, 7, 15, 7, 21, 3, 704288, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))}
field_serializer
しれっと追加されていたdict()
がmodel_dump()
に変わっていただけなら特に変化はありません。
何か変わっているところあるかなと思っていたところ、見つけました。
field_seralizer
説明をみるに、辞書化するときに任意の処理を挟める事ができるようです。
先程、独自メソッドを使っていましたが
field_seralizer
を使えば、以下のように書くことができます。
from datetime import datetime
from pydantic import BaseModel, field_serializer
from zoneinfo import ZoneInfo
class UserInfo(BaseModel):
name: str
age: int
dt: datetime
@field_serializer("dt")
def serialize_dt(self, dt: datetime) -> str:
return dt.isoformat()
dt = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
user_info = UserInfo(name="hogehoge", age=20, dt=dt)
print(user_info.model_dump())
# {'name': 'hogehoge', 'age': 20, 'dt': '2023-07-15T09:47:44.789119+09:00'}
field_serializer
をデコレータにし、対象となるフィールドを指定します。
後は関数内でカスタマイズして返却します。
返却値がフィールドキーの値として最終的に出力されます。
(例でいうところのdt:{日付の文字列}
)
model_serializer
model_serializer
を使えば、クラス自体の返却値を任意に変更できます。
from datetime import datetime
from pydantic import BaseModel, model_serializer
from zoneinfo import ZoneInfo
class UserInfo(BaseModel):
name: str
age: int
dt: datetime
@model_serializer
def serialize_dt(self) -> dict[str, str]:
return {"now_time": self.dt.isoformat()}
dt = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
user_info = UserInfo(name="hogehoge", age=20, dt=dt)
print(user_info.model_dump())
# {'now_time': '2023-07-15T09:55:08.056624+09:00'}
たまーに、キー・バリューを逆転して格納したい時があったのですが
これを使えばスマートに記述出来そうです。
pydanticで開発体験を向上させよう
pydanticは型を厳密に検証してくれるため
まるで静的型付け言語のような安心感がある開発を体感することができます。
pydanticはFastAPIと組み合わせて使われる事が多いですが
単体でも有効に使うことができます。
みなさんも是非試してみてください!
Discussion