skydum

個人的な作業記録とか備忘録代わりのメモ

pydanticの使い方

pydanticでネストされたモデルに値を入れる方法、ネストされたクラスを取得する方法、サブクラスの取得方法

  • 親 → 子供 → 孫の様に定義された(ネストされた)クラスに値を入れる必要があって調べた
  • 親に定義された子供クラスの情報を取得したかったため、親のクラスに定義されている情報から子供クラスの取得方法についても調べた

データの入れ方(Field aliasなし)

クラスの定義

  • 以下のように定義されているBaseModelに対してParentクラスからGrandchildクラスに定義されている変数全てに値を入れたい
class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default")


class Child(BaseModel):
    child_value: str = Field("child_default")
    grandchild: Grandchild = Field(None)


class Parent(BaseModel):
    parent_value: str = Field("parent_default")
    child: Child = Field(None)

データの入れ方

  • BaseModelに定義されている通りにdict形式で値を定義してキーワード引数を展開して渡すと一括で値を入れることができる
    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    # 成功パターン
    ok_model = Parent(**data)

    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_data', 'grandchild': {'grandchild_value': 'grandchild_data'}}}
    print(ok_model.dict())

ソース全文

aliasなしのパターン

from pydantic import BaseModel, Field


class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default")


class Child(BaseModel):
    child_value: str = Field("child_default")
    grandchild: Grandchild = Field(None)


class Parent(BaseModel):
    parent_value: str = Field("parent_default")
    child: Child = Field(None)


def main():
    """親→子供→孫のようにネストされたpydanticのモデルにdict形式で定義したデータを一括で入れる"""
    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    # 成功パターン
    ok_model = Parent(**data)

    # こちらの場合dict変換したときのキー名はクラスに設定された変数名が使われる
    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_data', 'grandchild': {'grandchild_value': 'grandchild_data'}}}
    print(ok_model.dict())


if __name__ == "__main__":
    main()

データの入れ方(Field aliasあり)

クラスの定義

class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

データの入れ方

    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    alias_data = {
        "親の値": "parent_data",
        "子供": {"子供の値": "child_data", "孫": {"孫の値": "grandchild_data"}},
    }

    # 成功パターン
    # Field aliasが設定されている時はdictで渡すキー名にaliasで指定した値を指定する必要がある
    ok_model = Parent(**alias_data)

    # dict変換したときのキー名はクラスに設定された変数名が使われる
    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_data', 'grandchild': {'grandchild_value': 'grandchild_data'}}}
    print(ok_model.dict())

    # Field aliasなしで利用したdataでは値が代入されない
    ng_model = Parent(**data)

    # {'parent_value': 'parent_default', 'child': None}
    print(ng_model.dict())


    # Parent.Configに定義されているConfiの定義を変更するとaliasが設定されている場合でも値を入れることができる
    # https://pydantic-docs.helpmanual.io/usage/model_config/
    Parent.Config.allow_population_by_field_name = True
    ng_model = Parent(**data)
    
    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_data', 'grandchild': {'grandchild_value': 'grandchild_data'}}}
    print(ng_model.dict())
class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

    class Config:
        # デフォルトでFalseで設定されている
        # Fieldにaliasが設定されている場合、値の代入にクラスの変数名を優先して利用するかどうか
        # デフォルトではFalseになっているのでFiledのaliasが優先して利用される
        # Trueにするとクラスに設定されているキー名が優先して利用される
        # ParentクラスでTrueに設定した場合Child, GrandchildについてもTrueが設定されているのと同じ様に動作する
        allow_population_by_field_name = False

ソース全文

aliasありのパターン

from pydantic import BaseModel, Field


class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

    class Config:
        # デフォルトでFalseで設定されている
        # Fieldにaliasが設定されている場合、値の代入にクラスの変数名を優先して利用するかどうか
        # デフォルトではFalseになっているのでFiledのaliasが優先して利用される
        allow_population_by_field_name = False


def main():
    """親→子供→孫のようにネストされたpydanticのモデルにdict形式で定義したデータを一括で入れる"""
    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    alias_data = {
        "親の値": "parent_data",
        "子供": {"子供の値": "child_data", "孫": {"孫の値": "grandchild_data"}},
    }

    # 成功パターン
    ok_model = Parent(**alias_data)

    # こちらの場合dict変換したときのキー名はクラスに設定された変数名が使われる
    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_data', 'grandchild': {'grandchild_value': 'grandchild_data'}}}
    print(ok_model.dict())

    # Fieldにaliasが設定されている時はaliasに指定した値で設定する必要がある
    # こちらは値が代入されない
    ng_model = Parent(**data)
    print(ng_model.dict())


if __name__ == "__main__":
    main()

Dict変換(Field aliasあり)

  • BaseModelをdict変換した時にFiledに設定したaliasを利用することができる

クラス定義

class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

    class Config:
        # デフォルトでFalseで設定されている
        # Fieldにaliasが設定されている場合、値の代入にクラスの変数名を優先して利用するかどうか
        # デフォルトではFalseになっているのでFiledのaliasが優先して利用される
        allow_population_by_field_name = False

dict変換のやり方

    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    alias_data = {
        "親の値": "parent_data",
        "子供": {"子供の値": "child_data", "孫": {"孫の値": "grandchild_data"}},
    }

    # 成功パターン
    ok_model = Parent(**alias_data)

    # dictする際にby_alias=Trueにした場合キー名はFieldに設定されたaliasが使われる
    # {'親の値': 'parent_data', '子供': {'子供の値': 'child_data', '孫': {'孫の値': 'grandchild_data'}}}
    print(ok_model.dict(by_alias=True))

    # Parent.Configに定義されているConfiの定義を変更するとaliasが設定されている場合でも値を入れることができる
    Parent.Config.allow_population_by_field_name = True
    ng_model = Parent(**data)

    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_default', 'grandchild': None}}
    print(ng_model.dict())

    # dictする際にby_alias=Trueにした場合キー名はFieldに設定されたaliasが使われる
    # {'親の値': 'parent_data', '子供': {'子供の値': 'child_default', '孫': None}}
    print(ng_model.dict(by_alias=True))

ソース全文

dict変換のやり方

from pydantic import BaseModel, Field


class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

    class Config:
        # デフォルトでFalseで設定されている
        # Fieldにaliasが設定されている場合、値の代入にクラスの変数名を優先して利用するかどうか
        # デフォルトではFalseになっているのでFiledのaliasが優先して利用される
        allow_population_by_field_name = False


def main():
    """親→子供→孫のようにネストされたpydanticのモデルにdict形式で定義したデータを一括で入れる"""
    data = {
        "parent_value": "parent_data",
        "child": {"child_value": "child_data", "grandchild": {"grandchild_value": "grandchild_data"}},
    }

    alias_data = {
        "親の値": "parent_data",
        "子供": {"子供の値": "child_data", "孫": {"孫の値": "grandchild_data"}},
    }

    # 成功パターン
    ok_model = Parent(**alias_data)

    # dictする際にby_alias=Trueにした場合キー名はFieldに設定されたaliasが使われる
    # {'親の値': 'parent_data', '子供': {'子供の値': 'child_data', '孫': {'孫の値': 'grandchild_data'}}}
    print(ok_model.dict(by_alias=True))

    # Parent.Configに定義されているConfiの定義を変更するとaliasが設定されている場合でも値を入れることができる
    Parent.Config.allow_population_by_field_name = True
    ng_model = Parent(**data)

    # {'parent_value': 'parent_data', 'child': {'child_value': 'child_default', 'grandchild': None}}
    print(ng_model.dict())

    # dictする際にby_alias=Trueにした場合キー名はFieldに設定されたaliasが使われる
    # {'親の値': 'parent_data', '子供': {'子供の値': 'child_default', '孫': None}}
    print(ng_model.dict(by_alias=True))

if __name__ == "__main__":
    main()

BaseModelで定義されたネストしたクラスの変数からサブのクラスを取得とFiledに定義されたalias名の取得

クラス定義

class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")

サブクラスの取得方法とクラスに定義されたalias名の取得

    # 親クラスに定義されているparent_valueのFieldに設定されているaliasを取得する
    # 親の値
    print(Parent.__fields__["parent_value"].field_info.alias)

    sub_class = Parent.__fields__["child"].type_

    # <class '__main__.Child'>
    print(sub_class)

    sub_sub_class = sub_class.__fields__["grandchild"].type_

    # <class '__main__.Grandchild'>
    print(sub_sub_class)

ソース全文

サブクラスの取得とalias名の取得

from pydantic import BaseModel, Field


class Grandchild(BaseModel):
    grandchild_value: str = Field("grandchild_default", alias="孫の値")


class Child(BaseModel):
    child_value: str = Field("child_default", alias="子供の値")
    grandchild: Grandchild = Field(None, alias="孫")


class Parent(BaseModel):
    parent_value: str = Field("parent_default", alias="親の値")
    child: Child = Field(None, alias="子供")


def get_subclass():
    """親→子供→孫のようにネストされたpydanticのモデルからサブクラスを取得する
    親(Parent)→childに定義されたクラスを取得する
    親に定義されたparent_valueに定義されたaliasを取得する
    """

    # 親クラスに定義されているparent_valueのFieldに設定されているaliasを取得する
    # 親の値
    print(Parent.__fields__["parent_value"].field_info.alias)

    sub_class = Parent.__fields__["child"].type_

    # <class '__main__.Child'>
    print(sub_class)

    sub_sub_class = sub_class.__fields__["grandchild"].type_

    # <class '__main__.Grandchild'>
    print(sub_sub_class)


if __name__ == "__main__":
    get_subclass()