SqlAlchemy 'after_insert' event on relationship?
Asked Answered
P

0

6

I have a setup which look something like this

class Topic(db.Model):
    __tablename__ = 'topic'

    id = db.Column(db.Integer, primary_key=True)
    parent = db.relationship(
        'Topic',
        secondary='parent_child_relation',
        primaryjoin='Topic.id == ParentChildRelation.child_topic_id',
        secondaryjoin='ParentChildRelation.parent_topic_id == Topic.id',
        backref='children',
        uselist=False
    )

class ParentChildRelation(db.Model):
    __tablename__ = 'parent_child_relation'

    id = db.Column(db.Integer, primary_key=True)
    child_topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), nullable=False)
    parent_topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), nullable=False)

and have set up events to watch for ParentChildRelation changes

@event.listens_for(ParentChildRelation, 'after_insert')
def parent_child_relation_inserted(mapper, connection, target):
    # DO STUFF HERE

The problem I'm running into is it seems that SqlAlchemy does not fire off those events when I do something like (I'm using Flask SqlAlchemy):

topic = Topic(id=new_id)
new_parent = Topic.query.get(anotherId)
topic.parent = new_parent
db.session.add(topic)
db.session.commit()

I would assume that the event handlers should be getting called, but the after_insert handler isn't getting called.

Is this a limitation of SqlAlchemy, or am I missing something?

Piggish answered 4/9, 2015 at 16:57 Comment(8)
is the record is going in to the parent_child_relation table? would expect you need to do a db.session.add(topic) somwhere? Also do you need a many-to-many relationship here? a lot simpler if you don't to just have a parent_id column.Nimbostratus
Whoops, yeah I do have the db.session.add(topic) in my actual code (will update my question to reflect that), and the ParentChildRelation is in fact making it into the db, but the after_insert handler is still not firing.Piggish
you might want to try listening to an attribute event instead? docs.sqlalchemy.org/en/latest/orm/events.html#attribute-eventsNimbostratus
I do need to keep the many-to-many relationship, as I am going to be allowing multiple inheritance in the future.Piggish
@Piggish if you do an explicit creation / add / flush of a ParentChildRelation does your event get triggered?Nimbostratus
Yep, and if I instead add the handler @event.listens_for(Topic.parent, 'set') that fires when i set topic.parent = new_parent, but unfortunately it seems to fire before the flush, which doesn't work for my purposes.Piggish
Can you do @event.listens_for(Topic.children, 'append')? Sorry, can't speak to weather this is expected behavior or not.Nimbostratus
Unfortunately, append (as well as any of the other collection events) doesn't fire when using uselist=False, as it seems to be treated as a scalar instead of a collection.Piggish

© 2022 - 2024 — McMap. All rights reserved.