概要
Custom Types という機能を使います
環境
- macOS 11.7.1
- Python 3.10.2
- sqlalchemy 1.4.43
- mysqlclient 2.1.1
インストール
- pipenv install sqlalchemy
- pipenv install mysqlclient
サンプルコード
"""TypeDcoratorを使ったサンプルモジュール."""
from dataclasses import dataclass
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import Column
from sqlalchemy.types import (Integer,
String)
from sqlalchemy.types import TypeDecorator
# セッション作成
engine = create_engine("mysql://root:@localhost/test?charset=utf8mb4")
SessionClass = sessionmaker(engine)
db_session = SessionClass()
Base = declarative_base()
class ProfileType(TypeDecorator):
"""カラム用の独自のプロファイルクラスを管理."""
impl = String
def __init__(self, *args, **kwargs):
"""クラスを指定する引数の定義."""
self.profile_class = kwargs.pop('profile_class')
TypeDecorator.__init__(self, *args, **kwargs)
def process_bind_param(self, value, dialect):
"""レコードのデータの型チェックをして返却."""
if value is not None:
if not isinstance(value, self.profile_class):
raise TypeError("Value should %s type" % self.profile_class)
return value.value
def process_result_value(self, value, dialect):
"""レコードのデータをオブジェクトに変換."""
if value is not None:
if not isinstance(value, str):
raise TypeError("value should have str type")
lang, framework = value.split(',')
return self.profile_class(lang, framework)
@dataclass
class Profile():
"""このクラスを使った独自カラムを定義する."""
lang: str
framework: str
class User(Base):
"""テーブル定義."""
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(50))
age = Column(Integer)
profile = Column(ProfileType(profile_class=Profile)) # ここに独自のクラスを使ったカラムを定義
# 動作確認
users = db_session.query(User).all()
for user in users:
print(user.profile.lang)
print(user.profile.framework)
ちょっと解説
ProfileType が sqlalchemy の Custom Types を使った独自の型になります
この型をカラム定義に使うことができます
データを受け取る際のクラスは Profile クラスになります
MySQL の内部的には CSV で保存されていることを想定しておりそれを分割して各フィールドに設定しています (process_result_value)
impl は独自実装元の型を定義します
process_bind_param と process_result_value は必ず実装するメソッドになります
最後に
わざわざ取り出したあとでオブジェクトに変換する必要がなくなるので便利です
0 件のコメント:
コメントを投稿