This is my implementation of what I asked for that based on @zzzeek helpful answer. First I've override Session.delete method. In this method if being deleted instance is Generic and DeleteHook classes instance then on_delete method called before sqlalchemy.orm.session.Session.delete method called. The main caveat here was that if sqlalchemy.orm.session.Session.delete method is execute in on_delete then after the last sqlalchemy.orm.session.Session.delete method called session.deleted will be reset. So I made a workaround: on_delete method should return query to objects that must be also be deleted. Then Session.delete at last step performed removing of all objects with autoflush off.
I think code can clear it out:
import sqlalchemy.orm.session
import sqlalchemy.orm.query
# other import statments . . .
Query = sqlalchemy.orm.query.Query
# Interface of Generic objects that should perform operations before deleted
class DeleteHook(object):
def on_delete(self, session):
"""
Hook performed before inherited Generic object marked for deletion.
It can return query of others object that also required to delete.
:param Session session: Current database session
:return: Query of the objects to being delete
:rtype: Query
"""
return []
class Session(sqlalchemy.orm.session.Session):
def delete(self, instance):
"""
Override delete method of the Session to execute on_delete
method of instance if required
"""
deleted = [instance]
if isinstance(instance, Generic) and isinstance(instance, DeleteHook):
deleted.extend(instance.on_delete(self))
# Autoflush required to be off otherwise
# if object with relationships deleted then
# session.deleted will be reset
self.autoflush = False
# All removed objects collected in the session.deleted set
for p_object in deleted:
super(Session, self).delete(p_object)
self.autoflush = True
class Tempable(Base):
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=True)
temporary = Column(Boolean, nullable=False)
class Generic(Base, DeleteHook):
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=True)
tempable_id = Column(Integer, ForeignKey(Tempable.id))
def on_delete(self, session):
"""
:param Session session: Current database session
:return: Query of the objects to being delete
:rtype: Query
"""
# Possible some others statements can be placed here
# . . .
# Select only temporary records
condition = and_(Tempable.id == self.tempable_id,
Tempable.temporary == 1)
return session.query(Tempable).filter(condition)