ok thanks. Unfortunately, I'll have to mess with my data model, but if there is no other way, I'll do it like that.
On Wed, Aug 23, 2017 at 4:19 AM, Mike Bayer <mike...@zzzcomputing.com> wrote: > On Tue, Aug 22, 2017 at 6:46 PM, cecemel <ruiz.felixr...@gmail.com> wrote: > > 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 ? > > so the way you have this set up, you have not only room->bed but you > also have delete,delete-orphan cascade. this indicates your intent > that a Bed object should be deleted when it is both not associated > with any Room, as well as when its parent Room is deleted. So the > behavior you are getting is what you specified. > > if you *dont* want Bed to be deleted when Room is deleted, you'd want > to remove that delete-orphan casacde. If you then want Bed to be > directly associated with House in the absense of Room, then yes you'd > add another column house_id to Bed with a corresponding > relationship(), and you'd need to make sure that is assigned as you > want as well when the objects go into the database. > > > > > > > > > > > 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> 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. > >> > To post to this group, send email to sqlal...@googlegroups.com. > >> > 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. > > -- > 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 a topic in the > Google Groups "sqlalchemy" group. > To unsubscribe from this topic, visit https://groups.google.com/d/ > topic/sqlalchemy/3pUrlkc0JDo/unsubscribe. > To unsubscribe from this group and all its topics, 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. > -- 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.