Search code examples
pythonsqlpostgresqlsqlalchemycascading-deletes

How can i get id of cascade deleted (or marked for delete) items in sqlalchemy?


When I cascade delete one item, I want get list of all deleted items id (primary key) including ids of deleted children. Is it possible?

My class looks like:

class Example(Base):
    __tablename__ = 'example'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('example.id', ondelete='CASCADE'), nullable=True)
    childrens = relationship('Example', backref=backref('parent', remote_side=[id], cascade="all, delete"))

and I query like:

session.query(Example).filter(Example.id == id).delete()

Solution

  • The only real solution that I know of is to use triggers. There is a generalized trigger for dealing with just this type of issue which has been committed to the PostgreSQL project as an installable extension for 9.2 (expected to be released this summer). If your python environment supports the PostgreSQL LISTEN/NOTIFY feature, you could download this and use it with 9.1 or 9.0. (We [the Wisconsin court system] have had it in production use with both for months.) You would need to be able to build it from source, I'm afraid, until version 9.2 is released. If you haven't done that before, the bottom of this page should be a good start:

    http://www.postgresql.org/docs/devel/static/contrib.html

    You can find source code for the extension here:

    http://git.postgresql.org/gitweb/?p=postgresql.git;a=tree;f=contrib/tcn;h=aa9c5813223a3996e22cabbf064d7243fa474c6c;hb=HEAD

    ... and you can currently find docs here:

    http://www.postgresql.org/docs/devel/static/tcn.html

    You would need to create a trigger which executes this trigger function on each table for which you want notification. It doesn't matter whether the DML is direct or indirect, as through the ON DELETE CASCADE clause of a foreign key definition. While the docs give an example where the function is attached to all DML, you can attach it just to DELETE if that's what you need, like this:

    create trigger example_tcn_trigger
      after delete on example
      for each row execute procedure triggered_change_notification();
    

    Full disclosure: I wrote this for the Wisconsin court system and they allowed me to share it with the PostgreSQL community.