On Wed, Oct 10, 2018 at 4:40 PM Benjamin Bertrand <bee...@gmail.com> wrote: > > Hi, > > I'm trying to index some data from my postgres database to elasticsearch. I > do something similar to what is described in this blog post: > https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-xvi-full-text-search > I store the new or modified objects in the before_flush event and want to > store a representation of the object in the after_commit event. > > My issue is that I have some relationships in my objects and the following > exception is raised by sqlalchemy: > sqlalchemy.exc.InvalidRequestError: This session is in 'committed' state; no > further SQL can be emitted within this transaction.
so you need to disable expire_on_commit, since you want the data there inside of after_commit there is no way around this: session = Session(engine, expire_on_commit=False) it's likely you might want to use a different event hook for what you're trying to do as the above is not ideal. after_flush_postexec() might be a better choice as that is prior to the expiration. then you need to load all the attributes somewhere ahead of time, here's doing it inside of before_flush: @event.listens_for(Session, "before_flush") def before_flush(session, flush_context, instances): # ... if isinstance(obj, (Device, Host)): # ... for attr in inspect(obj).attrs: getattr(obj, attr.key) where again, you can query the database inside of after_flush_postexec() without issue and no pre-load is needed. If you are trying to only print at the after_commit boundary, then place the state you want into your session._changes, like the actual strings you're looking to print, then just print those. > > Here is a short example to illustrate the issue: > > import itertools > from sqlalchemy import event, Column, Integer, String, ForeignKey, > create_engine > from sqlalchemy.orm import Session, relationship > from sqlalchemy.ext.declarative import declarative_base > > > Base = declarative_base() > > > @event.listens_for(Session, "before_flush") > def before_flush(session, flush_context, instances): > session._changes = [] > for obj in itertools.chain(session.new, session.dirty): > print(f"before_flush: {obj}") > if isinstance(obj, (Device, Host)): > session._changes.append(obj) > > > @event.listens_for(Session, "after_commit") > def after_commit(session): > print("after_commit") > for obj in session._changes: > print(obj.to_dict()) > > > class User(Base): > __tablename__ = "user_account" > id = Column(Integer, primary_key=True) > username = Column(String, nullable=False, unique=True) > > def __str__(self): > return self.username > > > class Device(Base): > __tablename__ = "device" > id = Column(Integer, primary_key=True) > name = Column(String) > user_id = Column(ForeignKey("user_account.id"), nullable=False, default=1) > host_id = Column(Integer, ForeignKey("host.id")) > user = relationship("User") > > def __str__(self): > return self.name > > def to_dict(self): > return { > "id": self.id, > "name": self.name, > "user": str(self.user), > "host": str(self.host), > } > > > class Host(Base): > __tablename__ = "host" > id = Column(Integer, primary_key=True) > name = Column(String) > devices = relationship("Device", backref="host") > > def __str__(self): > return self.name > > def to_dict(self): > return { > "id": self.id, > "name": self.name, > "devices": [device.to_dict() for device in self.devices], > } > > > # engine = create_engine("postgresql://postgres:secret@localhost/test", > echo=True) > engine = create_engine("postgresql://postgres:secret@localhost/test") > Base.metadata.drop_all(engine) > Base.metadata.create_all(engine) > session = Session(engine) > > user = User(id=1, username="John") > session.add(user) > session.commit() > > # If I don't query the user to add it to the session, I get: > # sqlalchemy.exc.InvalidRequestError: > # This session is in 'committed' state; no further SQL can be emitted within > this transaction. > myuser = session.query(User).get(1) > device1 = Device(name="mydevice") > session.add(device1) > session.commit() > > host1 = Host(name="test") > session.add(host1) > # This raises sqlalchemy.exc.InvalidRequestError when trying to access > host1.devices > session.commit() > > > How can I make sure that all relationships are in the session before the > after_commit event? > > -- > 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 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.