sqlalchemy: Load strategy doesn't work after commit() when lazy='raise'

Describe the bug

If a relationship has lazy='raise' and the object is queried with session.query(Model).options(joinedload(Model.rel)).one(), accessing to the relationship after session.commit() raises sqlalchemy.exc.InvalidRequestError.

To Reproduce

from sqlalchemy import Column, create_engine, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import joinedload, relationship, sessionmaker


engine = create_engine('sqlite:///:memory:')
Base = declarative_base()



class Feature(Base):
    __tablename__ = 'features'

    id = Column(Integer, primary_key=True)
    name = Column(String)


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    feature_id = Column(Integer, ForeignKey('features.id'))

    feature = relationship(Feature, lazy='raise')


Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

session = Session()

# Create one user and one feature
feature = Feature(name='my_feature')
session.add(feature)
session.flush()

user = User(feature=feature)
session.add(user)
session.commit()

# Retrieve the user
user = session.query(User).options(joinedload(User.feature)).one()

print(user.feature.name)  # displays "my_feature"

session.commit()

print(user.feature.name)  # raises

Error

  File "bug.py", line 48, in <module>
    print(user.feature.name)  # raises an error
  File "/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 286, in __get__
    return self.impl.get(instance_state(instance), dict_)
  File "/venv/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 722, in get
    value = self.callable_(state, passive)
  File "/venv/lib/python3.7/site-packages/sqlalchemy/orm/strategies.py", line 700, in _load_for_state
    self._invoke_raise_load(state, passive, "raise")
  File "/venv/lib/python3.7/site-packages/sqlalchemy/orm/strategies.py", line 662, in _invoke_raise_load
    "'%s' is not available due to lazy='%s'" % (self, lazy)
sqlalchemy.exc.InvalidRequestError: 'User.feature' is not available due to lazy='raise'

Versions.

  • SQLAlchemy: 1.13

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 15 (15 by maintainers)

Most upvoted comments

I think this is working as intended, since commit expires all objects, so you are reloading user for the second print. There is the expire_on_commit parameter to control this behaviour.