Restricted Session Event Listener

I am trying to add an event listener to the before_commit event of a SQLAlchemy session inside a Flask application. When performing the following

 def before_commit(session): for item in session: if hasattr(item, 'on_save'): item.on_save(session) event.listen(db.session, 'before_commit', before_commit) 

I get

 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "app.py", line 60, in <module> event.listen(db.session, 'before_commit', before_commit) File "C:\Python27\lib\site-packages\sqlalchemy\event\api.py", line 49, in listen _event_key(target, identifier, fn).listen(*args, **kw) File "C:\Python27\lib\site-packages\sqlalchemy\event\api.py", line 22, in _event_key tgt = evt_cls._accept_with(target) File "C:\Python27\lib\site-packages\sqlalchemy\orm\events.py", line 1142, in _accept_with "Session event listen on a scoped_session " sqlalchemy.exc.ArgumentError: Session event listen on a scoped_session requires that its creation callable is associated with the Session class. 

I cannot find the correct way to register an event listener. The documentation actually states that event.listen() also accepts scoped_session , but it doesn't seem like that !!


http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.SessionEvents

The listen () function will accept session objects, as well as the result of returning sessionmaker () and scoped_session ().

In addition, it adopts the Session class, which will apply listeners to all instance sessions globally.

+6
source share
2 answers

this means that the factory you passed scoped_session () should be sessionmaker ():

 from sqlalchemy.orm import scoped_session, sessionmaker, sessionmaker from sqlalchemy import event # good ss1 = scoped_session(sessionmaker()) @event.listens_for(ss1, "before_flush") def evt(*arg, **kw): pass # bad ss2 = scoped_session(lambda: Session) @event.listens_for(ss2, "before_flush") def evt(*arg, **kw): pass 
+4
source

To give another example, this code base will not work: https://sourceforge.net/p/turbogears1/code/HEAD/tree/branches/1.5/turbogears/database.py

 # bad def create_session(): """Create a session that uses the engine from thread-local metadata. The session by default does not begin a transaction, and requires that flush() be called explicitly in order to persist results to the database. """ if not metadata.is_bound(): bind_metadata() return sqlalchemy.orm.create_session() session = sqlalchemy.orm.scoped_session(create_session) 

Instead, there should be something like the following:

 # good class SessionMakerAndBind(sqlalchemy.orm.sessionmaker): def __call__(self, **kw): if not metadata.is_bound(): bind_metadata() return super(SessionMakerAndBind, self).__call__(**kw) sessionmaker = SessionMakerAndBind(autoflush=False, autocommit=True, expire_on_commit=False) session = sqlalchemy.orm.scoped_session(sessionmaker) 
0
source

All Articles