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)
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.