Hi Mike, 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)) Thank you and kind regards, Jaco On Wednesday, 17 May 2017 23:30:25 UTC+1, Mike Bayer wrote: > > > > On 05/17/2017 05:25 PM, Jaco Breitenbach wrote: > > Thank you, Jonathan, that wiki example has helped a lot. I've extended > > it a bit to also add the extra condition to joined tables. > > > > I want to take it one step further now and automatically convert > > session.delete()s into update statements (set is_deleted = true) instead > > of delete statements. I've experimented with a custom SessionExtension, > > don't use "Extensions", use the event system: > > > http://docs.sqlalchemy.org/en/rel_1_1/orm/events.html?highlight=before_flush#sqlalchemy.orm.events.SessionEvents.before_flush > > > > > > session.deleted.pop() # Remove the instance from the > > list of entities to be deleted > > ouch...that's not going to do anything. everything in Python is > mutable and it's kind of hard to make every collection everywhere that > only is a view of things immutable (though this is custom collection, > could be made immutable with a flag or something). To undo the delete, > add the object back, session.add(object). > > > > > > > > > > > > > Thank you and kind regards, > > Jaco > > > > > > On Tuesday, 16 May 2017 17:20:12 UTC+1, Jonathan Vanasco wrote: > > > > The FAQ > > > http://docs.sqlalchemy.org/en/latest/faq/sessions.html#how-do-i-make-a-query-that-always-adds-a-certain-filter-to-every-query > > > < > http://docs.sqlalchemy.org/en/latest/faq/sessions.html#how-do-i-make-a-query-that-always-adds-a-certain-filter-to-every-query> > > > > > > points to an example in the wiki: > > > https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery > > < > https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/PreFilteredQuery> > > > > > > > -- > > SQLAlchemy - > > The Python SQL Toolkit and Object Relational Mapper > > > > http://www.sqlalchemy.org/ > > > > To post example code, please provide an MCVE: Minimal, Complete, and > > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > > description. > > --- > > You received this message because you are subscribed to the Google > > Groups "sqlalchemy" group. > > To unsubscribe from this group and stop receiving emails from it, send > > an email to sqlalchemy+...@googlegroups.com <javascript:> > > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>. > > To post to this group, send email to sqlal...@googlegroups.com > <javascript:> > > <mailto:sqlal...@googlegroups.com <javascript:>>. > > Visit this group at https://groups.google.com/group/sqlalchemy. > > For more options, visit https://groups.google.com/d/optout. > -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.