Проверяет понимание жизненного цикла сессии SQLAlchemy и ленивой загрузки связанных данных.
В SQLAlchemy сессия управляет состоянием объектов и их связью с базой данных. Когда сессия закрывается, все объекты, которые были загружены через неё, переходят в состояние detached (отсоединённые). Это означает, что они больше не привязаны к какой-либо сессии и не могут автоматически загружать дополнительные данные из БД.
По умолчанию relationship использует стратегию lazy='select'. Это значит, что связанные данные загружаются только при первом обращении к атрибуту. Если вы обращаетесь к relationship после закрытия сессии, SQLAlchemy пытается выполнить новый SQL-запрос, но не находит активной сессии, что приводит к исключению DetachedInstanceError.
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
posts = relationship('Post')
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String)
user_id = Column(Integer, ForeignKey('users.id'))
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
user = session.query(User).first()
session.close()
# Ошибка: DetachedInstanceError
print(user.posts)joinedload или subqueryload для загрузки связанных данных вместе с основным запросом.session.add(user), но это не всегда удобно.# Пример с eager loading
from sqlalchemy.orm import joinedload
session = Session()
user = session.query(User).options(joinedload(User.posts)).first()
session.close()
# Теперь posts уже загружены, ошибки не будет
print(user.posts)Используйте явную загрузку связанных данных, если планируете работать с объектом после закрытия сессии. Это особенно полезно в веб-приложениях, где объекты могут передаваться на клиент или использоваться вне контекста запроса.