Thanks Mike Unfortunately it seems that after_transaction_end event executes twice: right before COMMIT and after after_commit event. Here what I see with echo=True and some prints:
2016-03-29 07:29:14,799 INFO sqlalchemy.engine.base.Engine INSERT INTO users (id) VALUES (?) 2016-03-29 07:29:14,799 INFO sqlalchemy.engine.base.Engine (3,) after_transaction_end 2016-03-29 07:29:14,799 INFO sqlalchemy.engine.base.Engine COMMIT after_commit after_transaction_end 2016-03-29 07:29:14,800 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2016-03-29 07:29:14,800 INFO sqlalchemy.engine.base.Engine INSERT INTO users (id) VALUES (?) 2016-03-29 07:29:14,800 INFO sqlalchemy.engine.base.Engine (2,) after_transaction_end 2016-03-29 07:29:14,801 INFO sqlalchemy.engine.base.Engine COMMIT after_commit after_transaction_end Consequently the event in after_commit never executes since token is already set. Here is the complete code: from sqlalchemy import Column, Integer, create_engine, event from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() engine = create_engine('sqlite:///:memory:', echo=True) Session = sessionmaker(bind=engine) class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) Base.metadata.create_all(engine) sess = Session() sess.add(User(id=1)) sess.commit() @event.listens_for(sess, 'after_commit') def foo(session): print('after_commit') if "my_token" not in session.info: print("never called") @event.listens_for(sess, "after_transaction_end") def bar(session, transaction): print('after_transaction_end') session.info["my_token"] = True sess.add(User(id=3)) sess.commit() sess.add(User(id=2)) sess.commit() On Tuesday, March 29, 2016 at 1:41:32 AM UTC+3, Mike Bayer wrote: > > > > On 03/28/2016 03:21 PM, Yegor Roganov wrote: > > I would like to get what I described in the subject: attach an event > > listener that will execute once after current transaction's successful > > commit (analogue to django's on_commit > > < > https://docs.djangoproject.com/en/1.9/topics/db/transactions/#django.db.transaction.on_commit> > > ). > > If current transaction rolls back, the event listener(s) should be > > discarded. > > set your own token to disable the event after the transaction ends: > > @event.listens_for(sess, 'after_commit') > def foo(session): > if "my_token" not in session.info: > print("do my event") > > > @event.listens_for(sess, "after_transaction_end") > def bar(session, transaction): > session.info["my_token"] = True > > > > > > > > I have tried using `event.listens_for(sess, 'after_commit', once=True)`, > > but probably as expected it will execute the callback if session > > continues to be used after rollback. Here is a complete source that you > > can play around with: > > | > > from sqlalchemy import Column, Integer, create_engine, event > > from sqlalchemy.orm import sessionmaker > > from sqlalchemy.ext.declarative import declarative_base > > > > > > Base = declarative_base() > > > > engine = create_engine('sqlite:///:memory:', echo=True) > > > > Session = sessionmaker(bind=engine) > > > > > > class User(Base): > > __tablename__ = 'users' > > > > id = Column(Integer, primary_key=True) > > > > Base.metadata.create_all(engine) > > > > sess = Session() > > > > sess.add(User(id=1)) > > sess.commit() > > > > > > @event.listens_for(sess, 'after_commit', once=True) > > def foo(session): > > print("shouldn't be called since the transaction will be rolled > back!") > > > > sess.add(User(id=1)) > > try: > > sess.commit() > > except: > > sess.rollback() > > > > sess.add(User(id=2)) > > sess.commit() # event callback will be called here > > > > | > > > > There is also an `after_transaction_end` event, but unfortunately I have > > not managed to bend it to my needs as well: 1) I haven't found public > > API to determine the transaction state when the callback executes 2) If > > an event listener is attached in a subtransaction, the callback will get > > called when the subransaction commits, while I'd like to the callback to > > only get called when the 'outermost' transaction commits successfully. > > > > > > Greatly appreciate any help. > > > > -- > > You received this message because you are subscribed to the Google > > Groups "sqlalchemy" group. > > To unsubscribe from this group and stop receiving emails from it, send > > an email to sqlalchemy+...@googlegroups.com <javascript:> > > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>. > > To post to this group, send email to sqlal...@googlegroups.com > <javascript:> > > <mailto:sqlal...@googlegroups.com <javascript:>>. > > Visit this group at https://groups.google.com/group/sqlalchemy. > > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.