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.

Reply via email to