SQLAlchemyのdeclarative_base関連

PythonのORMであるSQLALchemy。 とても便利なモジュールですが、巨大なモジュールで構造も複雑です。

そのSQLALchemyでモデルとデーターベースへのマッピングを同時に行うために利用する、declarative_baseの備忘録(なにぶん把握出来ておりませので間違い等あるかと思います)です。

まず、モデルの構築方法を。

from sqlalchemy import MetaData
from sqlalchemy.ext.declarative import declarative_base

modelClasses = {}
modelBase = declarative_base(class_registry = modelClasses, metadata=MetaData())

データーベースのテーブルにマッピングされるモデルを作成するには、"declarative_base"のインスタンスから派生する必要があります。

"MetaData"はデーターベースのマッピングを行う際に必要になるもので、上記のように行うことで派生クラスのテーブルを一括してマッピングすることが可能です。

"class_registry"は、小さなシステムでは必要になることはあまりありませんが、動的なシステムを構築する際に、どのようなモデルが存在するのか管理する際に必要になると思われます。上記では単純にDictを渡すことで、名前とクラスの辞書が生成されます。

from sqlalchemy import Column, Integer, String, PickleType, Sequence, DateTime, ForeignKey, Table
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy.orm import synonym

class Test(modelBase):
  __tablename__ = 'test'

  id = Column(Integer, Sequence('test_id_seq'), primary_key=True)

  _data = Column(PickleType)

  def get_data(self):
      return self. _data

  def set_data(self, data):
      self. _data = data

  @declared_attr
  def data(self):
      return synonym('_data', descriptor=property(self.get_data, self.set_data))

__tablename__ : テーブル名。必ず必要で定義されていない場合はエラーとなる

プライマリーキーが必ず必要(上記コードでは、idに該当)で定義されていない場合はエラーとなる。

モデルの値を処理する際、例えばパスワードのフィールドを用意する場合、値をセットする時にはハッシュ化された値をデーターベースに書き込むことになります。

そのようなケースの際、Pythonでは通常propertyを使いますが、上記のように読み込み、書き込み関数を定義し、declared_attrに続くコードを書くことで実現出来ます。


さて、class_registryが必要な状況になってきますと、どのようなモデルでも値をセット出来るような関数の必要度が上がってきます。

下記のように行うことで、上記のようにセッターがある際でも、正しいカラム名を取得します。

columns = Test.__table__.columns
print columns.keys()

上記のように、__table__を介すことで_dataではなく、セッターのdataという名前が返ります。

また、例えばTest.idは、Columnのインスタンスではなく、sqlalchemy.orm.attributes.InstrumentedAttribute型のインスタンスになっています。

Test.dictでこれらの辞書を取得出来ますが、InstrumentedAttributeは明らかに内部用の型で、リレーションを構築した際にも同じ型で定義されているため、純粋にカラムの一覧が欲しい際には、上記の__table__を介す必要があるようです。

カラムへのアクセスは下記のように行います。

data = getattr(TestInstance,  'data')

__getitem__などは定義されていないため、getattr及びsetattrを使います。

次回はrelationのことをメモりたいと思います。