sqlalchemyでうれしいところ。(concrete table inheritanceで継承元のクラスで検索した場合に適切な子クラスにマッピングしたオブジェクトを返してくれるところ)

sqlalchemy は、concrete table inheritanceで定義したモデルがあるとする。
それらのモデルを継承元のクラスで検索した場合に、検索結果のqueryは適切な子クラスにマッピングしたオブジェクトのリストとなって返ってくるところ。これがうれしい。

e.g.

例はRoleというモデルを継承して

  • Knight
  • Magician
  • Chief

というモデルが定義されている。これらの各モデルをテーブルに格納した後、継承元となる。
Roleで検索したとき、返ってくるquery listは全てより詳細な子クラスにマッピングされている。素晴らしい。

import sqlalchemy as sa
import sqlalchemy.orm as orm
# from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
Session = orm.scoped_session(orm.sessionmaker())

class Skil(Base):
    __tablename__ = "skil"
    id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
    name = sa.Column(sa.String(255), unique=True)
class Role(Base):
    __tablename__ = "role"
    query = Session.query_property()
    id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
    name = sa.Column(sa.String(255), unique=True)
    discriminator = sa.Column("type", sa.String(32), nullable=False)
    __mapper_args__ = {"polymorphic_on": discriminator}

    def __repr__(self):
        return "%s:name=%s" % (self.__class__.__name__, self.name)
class Magician(Role):
    __tablename__ = "magician"
    type = "magician"
    __mapper_args__ = {"polymorphic_identity": type}
    id = sa.Column(sa.Integer, sa.ForeignKey("role.id"), primary_key=True)

class Knignht(Role):
    __tablename__ = "knignht"
    type = "knignht"
    __mapper_args__ = {"polymorphic_identity": type}
    id = sa.Column(sa.Integer, sa.ForeignKey("role.id"), primary_key=True)

class Thief(Role):
    __tablename__ = "tief"
    type = "thief"
    __mapper_args__ = {"polymorphic_identity": type}
    id = sa.Column(sa.Integer, sa.ForeignKey("role.id"), primary_key=True)

engine = sa.create_engine("sqlite://")
# engine.echo = True

Session.configure(bind=engine)
Base.metadata.bind = engine
Base.metadata.create_all()

Session.add_all([Magician(name="foo"), Knignht(name="boo"), Thief(name="bar")])
import transaction
transaction.commit()

print Role.query.all()
# [Magician:name=foo, Knignht:name=boo, Thief:name=bar]