SQLALchemy "after_insert" doesn't update target object fields

The thing with 'after_insert' kind of handlers is to use the connection directly. Here's how I did it:

class Link(db.Model):
    "News link data."

    __tablename__ = 'news_links'

    id = db.Column(db.BigInteger, primary_key=True)
    slug = db.Column(db.String, unique=True) #, nullable=False 

    url = db.Column(db.String, nullable=False, unique=True)
    title = db.Column(db.String)
    image_url = db.Column(db.String)
    description = db.Column(db.String)

@db.event.listens_for(Link, "after_insert")
def after_insert(mapper, connection, target):
    link_table = Link.__table__
    if target.slug is None:
        connection.execute(
            link_table.update().
            where(link_table.c.id==target.id).
            values(slug=slugify(target.id))
        )

I ended up solving this by ditching the Mapper Event approach and using Flask's Signalling Support instead.

Basically, you can register "signals" on your model, which are essentially callback functions that are called whenever a specific kind of event happens. In my case, the event is an "update" on my model.

To configure the signals, I added this method to my app.py file:

def on_models_committed(sender, changes):
    """Handler for model change signals"""
    for model, change in changes:
        if change == 'insert' and hasattr(model, '__commit_insert__'):
            model.__commit_insert__()
        if change == 'update' and hasattr(model, '__commit_update__'):
            model.__commit_update__()
        if change == 'delete' and hasattr(model, '__commit_delete__'):
            model.__commit_delete__()

Then, on my model, I added this function to handle the update event:

 # Event methods
def __commit_update__(self):

    # create a new db session, which avoids the ResourceClosedError
    session = create_db_session()

    from techmuseum.modules.sensors.models import SoundsRaw
    # Get the SoundsRaw record by uuid (self contains the object being updated, 
    # but we can't just update/commit self -- we'd get a ResourceClosedError)
    sound = session.query(SoundsRaw).filter_by(uuid=self.uuid).first()

    # Extract text from audio file
    audio_text = compute_text_from_audio_file(sound)

    # Update the 'text' field of the sound
    sound.text = audio_text

    # Commit the update to the sound
    session.add(sound)
    session.commit()

def create_db_session():
    # create a new Session
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    psql_url = app.config['SQLALCHEMY_DATABASE_URI']
    some_engine = create_engine(psql_url)
  
    # create a configured "Session" class
    session = sessionmaker(bind=some_engine)

    return session