I am Charmie

メモとログ

SQLAlchemy: ORMと共に生きる

ORMを使わない実装を進めていたら,insert文を使うとデータのIDを指定できない問題が生じた. 自動で設定されるIDが0オリジンではなく1オリジンな点が現プロジェクトにおいて致命的な問題になってしまうため,ORMの使用で解決した.

ORM

上述した理由からSQLAlchemyのORMについて調べた.

テーブルメタデータをORMで定義

  • ORMを使うとき,テーブルメタデータを宣言する過程はmapped classを宣言する過程と組み合わされる.
  • mapped classはテーブルのカラムに対応するクラス属性を持つpythonのクラス
  • mapped classを実現するための最も一般的な方法はdeclarativeとして知られ,このdeclarativeによってユーザが定義するクラスとテーブルメタデータを一度に宣言できる

  • declarative_baes型オブジェクトは宣言するORM mapped classのための基底クラスとして使える

  • 一つの基底クラス(declarative_base)から派生したクラスは,同じテーブルのテーブルとして扱われる
  • あるテーブルのカラムはそのテーブル内の全データに共通するため,カラムは派生クラスのinit内ではなくクラス属性として宣言される
  • 同一IDのデータを登録しようとしたらちゃんと異常終了した
# registryとdeclarative baseの生成を同時に行う
from sqlalchemy.orm import declarative_base
Base = declarative_base()

# mapped classの宣言
from sqlalchemy.orm import relationship
class User(Base):
    __tablename__ = 'user_account'

    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    fullname = Column(String)

    addresses = relationship("Address", back_populates="user")

    def __repr__(self):
       return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

class Address(Base):
    __tablename__ = 'address'

    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey('user_account.id'))

    user = relationship("User", back_populates="addresses")

    def __repr__(self):
        return f"Address(id={self.id!r}, email_address={self.email_address!r})"

# CREATE statement文をdeclarative_baseに紐付ける

engine = create_engine('sqlite:///test.db')
# 既存のテーブルを削除する場合は以下のコメントアウトを解除
# Base.metadata.drop_all(bind=self.database)
Base.metadata.create_all(bind=self.database)
Session = sessionmaker(bind=self.database)
session = Session()