Open5

Pydantic を調べて使ってみる-1

ikeponikepon

https://docs.pydantic.dev/latest

FastAPI でSQLModel を使ってるので Pydantic について知ろうと思ってまとめる
https://fastapi.tiangolo.com/ja/tutorial/sql-databases/

  • Pydantic はバリデーションとシリアライズ(JSON と Python オブジェクトの変換)、型定義を担当
  • SQLAlchemy は ORM
  • SQLModel が上記 2 つを組み合わせて、1つのモデルを定義することで、DBとのやり取りと API のデータバリデーションなどをできるようにしている
ikeponikepon
  • Pydantic は Python のための「型ヒントベースのデータバリデーションとシリアライズライブラリ」

    • 型ヒントを活用して、 データの構造や型の正しさを検証(validate) できる
  • ※ FastAPI で使ってるから調べて見たが、FastAPI の ORM が sqlmodel で、こいつが Pydantic に依存してる

ikeponikepon

用語整理

  • schema: データ構造
  • Model: 構造化されたデータの設計図(スキーマ) を表すクラスで、 BaseModel を継承したもの
ikeponikepon

サンプル

from pydantic import BaseModel, ConfigDict


class User(BaseModel):
    id: int
    name: str = 'Jane Doe'

    model_config = ConfigDict(str_max_length=10) 

user インスタンス作成

user = User(id='123')

assert user.name == 'Jane Doe'  # デフォルトで設定してる
assert user.id == 123  
assert isinstance(user.id, int)

model_dump() で dict(辞書型) に出せる

dict(user) でも出せるが、入れ子になった場合に出力してくれない

assert user.model_dump() == {'id': 123, 'name': 'Jane Doe'}

その他、いかにいろいろとメソッドとかありそう

https://docs.pydantic.dev/latest/concepts/models/#model-methods-and-properties

Model で定義した方に強制的に cast される

strict mode があって、それだと変換してくれない
コレクション型は list や dict のような具体的な型を使うべき
https://docs.pydantic.dev/latest/concepts/models/#data-conversion

from pydantic import BaseModel


class Model(BaseModel):
    a: int
    b: float
    c: str


print(Model(a=3.000, b='2.72', c=b'binary data').model_dump())
#> {'a': 3, 'b': 2.72, 'c': 'binary data'}

extra data(上記例なら Model(a=3.000, b='2.72', c=b'binary data', d='extra_data') みたいな d を入れた場合、エラーにはならないし、インスタンスにも保存しない
model_config = ConfigDict(extra='allow') を設定すると保持するようになる
allow 以外のオプションは以下

  • ignore: 余分なものは無視する: これがデフォルト
  • forbid: 余計なものを禁止する
class Model(BaseModel):
    x: int

    model_config = ConfigDict(extra='allow')


m = Model(x=1, y='a')  
assert m.model_dump() == {'x': 1, 'y': 'a'}
assert m.__pydantic_extra__ == {'y': 'a'}
ikeponikepon

いろいろ見ていこうと思ったけど、先に SQLModel を見るべきなので、一旦ここまで