Hello, thanks again for the answer. Perhaps my case was not clear enough. To make it a bit more explicit, I updated the example accordingly.
from sqlalchemy import event from sqlalchemy import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, backref, relationship Base = declarative_base() ######################################################################################### # MODEL ######################################################################################### class House(Base): __tablename__ = 'house' id = Column(Integer, primary_key=True) rooms = relationship("Room", backref=backref("house", lazy="joined"), cascade='all, delete-orphan') class Room(Base): __tablename__ = 'room' id = Column(Integer, primary_key=True) house_id = Column(Integer, ForeignKey('house.id')) beds = relationship("Bed", backref=backref("room", lazy="joined"), cascade='all, delete-orphan') class Bed(Base): __tablename__ = 'bed' id = Column(Integer, primary_key=True) room_id = Column(Integer, ForeignKey('room.id')) ######################################################################################### # CONFIG ######################################################################################### def setup(): engine = create_engine("sqlite://", echo=True) Base.metadata.bind = engine Base.metadata.create_all(engine) SessionFactory = sessionmaker( bind=engine ) event.listen(SessionFactory, 'deleted_to_detached', listener_bed_has_been_removed) return SessionFactory def listener_bed_has_been_removed(session, instance): if type(instance) is not Bed: return # so, in this example, this function should be called 3 times. # The first time it is called, I get no problems, I can access instance.room.house_id the call proceeds # The second bed is a problem, I get the error # "sqlalchemy.orm.exc.DetachedInstanceError: Parent instance <Bed at 0x7f24fe14bb70> is not bound to a Session; lazy load operation of attribute 'room' cannot proceed" # SO, my question is: is there ANY way to keep these references to parents in this function? bed_id = instance.id house_id = instance.room.house_id print("execute a service call to external service here bed_id {}, house_id {}".format(bed_id, house_id)) if __name__ == "__main__": session_factory = setup() session = session_factory() session.add(House(id=1)) session.add(Room(id=1, house_id=1)) session.add(Bed(id=1, room_id=1)) session.add(Bed(id=2, room_id=1)) session.add(Bed(id=3, room_id=1)) session.commit() room = session.query(Room).get(1) session.delete(room) session.commit() session.close() So, for this example, I am looking for a solution to keep the references to the 'house' from the 'bed' model after flush (any solution would be good). Is there perhaps a way to dynamically set a property in 'bed' -model (e.g house_id), once 'room'-backref has been loaded ? On Tuesday, August 22, 2017 at 5:36:39 PM UTC+2, Mike Bayer wrote: > > you would need to illustrate an MCVE of what's happening. objects > don't "lose track" of their related objects unless yes, you deleted > them, in which case you should not expect that they would be there. > when the object is expired, it will go to reload them, and they'll be > gone. > > On Tue, Aug 22, 2017 at 11:05 AM, cecemel <ruiz.fe...@gmail.com > <javascript:>> wrote: > > @update: > > > > calling the flush doen't seem to make any difference. At some point, the > > object looses track of it's grandparents > > > > > > On Tuesday, August 22, 2017 at 3:57:23 PM UTC+2, cecemel wrote: > >> > >> Hi, > >> > >> so, I'm currently facing this issue, where I would like to do some > calls > >> to an external service, when my object has been deleted within a flush. > >> For this operation to occur, I need the id from my model object, but > also > >> the id from the parent of the parent object model. There are cases, > where I > >> am unable to access them (I guess, depending of the order of the > execution) > >> and I am unsure on what to do next. > >> > >> So if you're willing to give me some advice, would be awesome. > >> > >> Here is a dummy model: > >> > >> from sqlalchemy import event > >> > >> from sqlalchemy import * > >> from sqlalchemy.ext.declarative import declarative_base > >> from sqlalchemy.orm import sessionmaker, backref, relationship > >> > >> Base = declarative_base() > >> > >> > >> > >> > ######################################################################################### > > > >> # MODEL > >> > >> > ######################################################################################### > > > >> class House(Base): > >> __tablename__ = 'house' > >> id = Column(Integer, primary_key=True) > >> rooms = relationship("Room", > >> backref=backref("house", lazy="joined"), > >> cascade='all, delete-orphan') > >> > >> > >> class Room(Base): > >> __tablename__ = 'room' > >> id = Column(Integer, primary_key=True) > >> house_id = Column(Integer, ForeignKey('house.id')) > >> beds = relationship("Bed", > >> backref=backref("room", lazy="joined"), > >> cascade='all, delete-orphan') > >> > >> > >> class Bed(Base): > >> __tablename__ = 'bed' > >> id = Column(Integer, primary_key=True) > >> room_id = Column(Integer, ForeignKey('room.id')) > >> > >> > >> > >> > ######################################################################################### > > > >> # CONFIG > >> > >> > ######################################################################################### > > > >> def setup(): > >> engine = create_engine("sqlite:///foo.db", echo=True) > >> > >> Base.metadata.bind = engine > >> Base.metadata.create_all(engine) > >> > >> SessionFactory = sessionmaker( > >> bind=engine > >> ) > >> > >> event.listen(SessionFactory, 'deleted_to_detached', > >> listener_bed_has_been_removed) > >> > >> return SessionFactory > >> > >> > >> def listener_bed_has_been_removed(session, instance): > >> if type(instance) is not Bed: > >> return > >> > >> bed_id = instance.id > >> house_id = instance.room.house.id # this is NOT ALWAYS there. > >> Depending on the order of the execution I guess > >> > >> print("execute the service call to external service here bed_id {}, > >> house_id {}".format(bed_id, house_id)) > >> > >> > >> > >> > >> So my question(s): > >> > >> Is there a clean way to always acces this parent's parent attribute? > >> > >> If not, would be starting a new session and query it from the event > >> handler be an option? (is it not dangerous, because it seems to work) > >> > >> Additional quirk, I am working within a transaction manager > (pyramid_tm) > >> and ZopeTransactionExtension() > >> > >> Thanks! > >> > >> > >> More information about the system: > >> > >> SQLAlchemy 1.1.13 > >> > >> Python 3.5 > >> > >> Postgres 9.6 > > > > -- > > 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:>. > > To post to this group, send email to 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.