読者です 読者をやめる 読者になる 読者になる

MapperExtensionを使う

SQLAlchemy

sqlalchemy.orm.MapperExtensionを使うと、オブジェクトの生成、変更、消去等のタイミングで任意の処理を行うことができます。
この機能を使うと、django.dispatchと使ったこれと同じことができそうです。

from datetime import date
from sqlalchemy import *
from sqlalchemy.orm import *

# SQLiteメモリーデータベースに接続
md = MetaData('sqlite://')
md.bind.echo = True

# テーブル定義
cat = Table('cat', md,
            Column('id', Integer, primary_key=True),
            Column('name', Unicode(50), nullable=False),
            Column('birthday', Date, nullable=False),
            )
# テーブルを作る
md.create_all()

# モデルクラスの定義
class Cat(object):
    def __init__(self, name, birthday):
        self.name = name
        self.birthday = birthday

    def __repr__(self):
        return '<Cat "%s">' % self.name

# Mapper拡張の定義
class MyMapperExtension(MapperExtension):
    def after_delete(self, mapper, connection, instance):
        print "Deleted %r" % instance

    def after_insert(self, mapper, connection, instance):
        print "Inserted %r" % instance

    def after_update(self, mapper, connection, instance):
        print "Updated %r" % instance

# Mapperの定義
mapper(Cat, cat, extension=MyMapperExtension())

# テストデータを作成
sess = create_session()
rudolf = Cat(u'Rudolf', date(2005, 12, 4))
sess.save(rudolf)

# セッションをフラッシュしてデータをDBに反映
sess.flush()

# 一度セッション内のオブジェクトを消去する
sess.clear()

# もう一度オブジェクトを取得する。0.4の書き方。
# 0.3ならば、sess.query(Cat).select()[0]とか?
rudolf = sess.query(Cat).one()

# 誕生日を変更して保存
rudolf.birthday = date(2005, 12, 25)
sess.flush()

# セッション内のオブジェクトを消去
sess.clear()

# もう一度オブジェクトを取得して、今度は消去。
rudolf = sess.query(Cat).one()
sess.delete(rudolf)
sess.flush()

実行ログを確認すると、COMMITが呼ばれる前にMapper Extensionのafter_XXXメソッドが呼ばれていることが分かります。例えば、新規レコード挿入のログは次のようになります。

2007-08-20 12:54:55,092 INFO sqlalchemy.engine.base.Engine.0x..d0 BEGIN
2007-08-20 12:54:55,092 INFO sqlalchemy.engine.base.Engine.0x..d0 INSERT INTO ca
t (name, birthday) VALUES (?, ?)
2007-08-20 12:54:55,092 INFO sqlalchemy.engine.base.Engine.0x..d0 ['Rudolf', '20
05-12-04']
Inserted <Cat "Rudolf">
2007-08-20 12:54:55,108 INFO sqlalchemy.engine.base.Engine.0x..d0 COMMIT