これは他のイベントベースの回答と一緒に続きますが、私はあなたの正確な問題をほぼ解決するためにそれを書いたので、私はこのコードを投稿すると思いました:
以下のコードは、フラッシュが発生したときにすべての新規、変更、および削除されたオブジェクトを蓄積するSessionExtensionクラスを登録し、セッションが実際にコミットまたはロールバックされたときにキューをクリアまたは評価します。次に、外部ファイルが添付されているクラスについて、SessionExtensionが適切に呼び出すメソッド、、、および/またはメソッドをobj.after_db_new(session)
実装obj.after_db_update(session)
しました。obj.after_db_delete(session)
次に、これらのメソッドにデータを入力して、外部ファイルの作成/保存/削除を処理できます。
注:これはSqlAlchemyの新しいイベントシステムを使用してよりクリーンな方法で書き直すことができるとほぼ確信しています。他にもいくつかの欠陥がありますが、本番環境で動作しているため、更新していません:)
import logging; log = logging.getLogger(__name__)
from sqlalchemy.orm.session import SessionExtension
class TrackerExtension(SessionExtension):
def __init__(self):
self.new = set()
self.deleted = set()
self.dirty = set()
def after_flush(self, session, flush_context):
# NOTE: requires >= SA 0.5
self.new.update(obj for obj in session.new
if hasattr(obj, "after_db_new"))
self.deleted.update(obj for obj in session.deleted
if hasattr(obj, "after_db_delete"))
self.dirty.update(obj for obj in session.dirty
if hasattr(obj, "after_db_update"))
def after_commit(self, session):
# NOTE: this is rather hackneyed, in that it hides errors until
# the end, just so it can commit as many objects as possible.
# FIXME: could integrate this w/ twophase to make everything safer in case the methods fail.
log.debug("after commit: new=%r deleted=%r dirty=%r",
self.new, self.deleted, self.dirty)
ecount = 0
if self.new:
for obj in self.new:
try:
obj.after_db_new(session)
except:
ecount += 1
log.critical("error occurred in after_db_new: obj=%r",
obj, exc_info=True)
self.new.clear()
if self.deleted:
for obj in self.deleted:
try:
obj.after_db_delete(session)
except:
ecount += 1
log.critical("error occurred in after_db_delete: obj=%r",
obj, exc_info=True)
self.deleted.clear()
if self.dirty:
for obj in self.dirty:
try:
obj.after_db_update(session)
except:
ecount += 1
log.critical("error occurred in after_db_update: obj=%r",
obj, exc_info=True)
self.dirty.clear()
if ecount:
raise RuntimeError("%r object error during after_commit() ... "
"see traceback for more" % ecount)
def after_rollback(self, session):
self.new.clear()
self.deleted.clear()
self.dirty.clear()
# then add "extension=TrackerExtension()" to the Session constructor