skydum

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

pydanticで_(アンダースコア)から始まる変数を利用する方法

pydanticで_から始まるクラス変数を利用できないので、利用できるようにする

通常の問題がないパターン

from pydantic import BaseModel, Field


class Users(BaseModel):
    id: str = Field(None)
    name: str = Field(None)
    data: str = Field(None)


u = Users(id="a", name="b", data="data")

# id='a' name='b' data='data'
print(u)

# {'id': 'a', 'name': 'b', 'data': 'data'}
print(u.dict())

問題があるパターン

  • _idの様に変数名が_から始まる場合、pydanticでは値を入れられるが取得ができなくなる
  • private変数として扱われて外部から参照できなくなる?
from pydantic import BaseModel, Field


class Users(BaseModel):
    _id: str = Field(None)
    name: str = Field(None)
    data: str = Field(None)


u = Users(_id="a", name="b", data="data")

# name='b' data='data'
print(u)

# {'name': 'b', 'data': 'data'}
print(u.dict())

_から始まる変数を利用できるようにする

方法1. Field(alias)を利用する

  • pydanticで標準で用意されているFieldにaliasを割り当てる方法で変数を定義し、dictに変換する時にaliasに指定した値で変換する
from pydantic import BaseModel, Field


class Users(BaseModel):
    id: str = Field(None, alias="_id")
    name: str = Field(None)
    data: str = Field(None)


u = Users(_id="a", name="b", data="data")

# id='a' name='b' data='data'
print(u)

# {'_id': 'a', 'name': 'b', 'data': 'data'}
print(u.dict(by_alias=True))

方法2. pydanticのdefにモンキーパッチを当てて問題を回避する

# monkey patch to get underscore fields
def is_valid_field(name:str):
    if not name.startswith('__'):
        return True
    elif name == '__root__':
        return True

pydantic.main.is_valid_field = is_valid_field

モンキーパッチを当てたソース

  • これでField(alias)を使わなくても問題なく_から始まる変数名を利用できるようになる
  • こだわりがないのなら方法1のField(alias)を使った方がいいと思う
import pydantic
from pydantic import BaseModel, Field


def is_valid_field(name: str):
    if not name.startswith("__"):
        return True
    elif name == "__root__":
        return True


pydantic.main.is_valid_field = is_valid_field


class Users(BaseModel):
    _id: str = Field(None)
    name: str = Field(None)
    data: str = Field(None)


u = Users(_id="a", name="b", data="data")

# _id='a' name='b' data='data'
print(u)

# {'_id': 'a', 'name': 'b', 'data': 'data'}
print(u.dict())