Thank you very much. I've managed to get it working after a fashion. Unfortunately this technique seems to interfere with the automatic clean-up of the secondary (mapping) table in the case of a many-to-many relationship. In the example below I have a contact_group table and user table and a many-to-many relationship set up via a contact_group_user_map table. Since I've used backref in defining the relationship, I expect the row in contact_group_user_map to automatically be deleted when I do session.delete(userObj). This works perfectly as long as the before_flush handler is disabled. If I intercept the delete of userObj and turn it into an update, the delete from contact_group_user_map no longer happens. I've noticed that the list of objects in session.deleted which is passed to the before_flush handler does not include the contact_group_user_map entity, so I guess the determination to delete the row from contact_group_user_map takes place after the before_flush handler returns. Do you have any advice on resolving this issue?
from sqlalchemy import create_engine, event, BigInteger, Column, DateTime, Float, ForeignKey, Index, Integer, String, text
from sqlalchemy.orm import attributes, relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_repr import PrettyRepresentableBase
Base = declarative_base(cls=PrettyRepresentableBase)
metadata = Base.metadata
engine = None
Session = None
def handle__before_flush(session, flush_context, instances):
print("handle__before_flush()")
for instance in session.deleted:
print(instance)
if not attributes.instance_state(instance).has_identity:
continue
if not hasattr(instance, '_deleted'):
continue
# instance._deleted = True
# session.add(instance)
def getSession(conn):
global engine, Session
if engine is None or Session is None:
engine = create_engine(conn, echo=True)
Session = sessionmaker(bind=engine, query_cls=SoftDeleteQuery)
event.listen(Session, 'before_flush', handle__before_flush)
return Session()
class ContactGroup(Base):
__tablename__ = 'contact_group'
id = Column(BigInteger, primary_key=True)
_deleted = Column(Integer, nullable=False, server_default=text("'0'"))
name = Column(String(200), nullable=False)
description = Column(String(1000))
users = relationship("User", secondary="contact_group_user_map", backref="contact_groups")
class ContactGroupUserMap(Base):
__tablename__ = 'contact_group_user_map'
id = Column(BigInteger, primary_key=True)
contact_group_id = Column(ForeignKey(u'contact_group.id'), nullable=False, index=True) user_id = Column(ForeignKey(u'user.id'), nullable=False, index=True)
contact_group = relationship(u'ContactGroup')
user = relationship(u'User')
class User(Base):
__tablename__ = 'user'
id = Column(BigInteger, primary_key=True)
_deleted = Column(Integer, nullable=False, server_default=text("'0'"))
username = Column(String(200), nullable=False, unique=True)
password = Column(String(1000))