Метод expire_all
Метод expire_all класса Session
помечает все объекты, находящиеся в сессии,
как устаревшие (expired). Это означает, что
при следующем обращении к любому атрибуту
таких объектов SQLAlchemy автоматически
выполнит SQL-запрос и загрузит актуальные
данные из базы. Метод не принимает параметров.
Метод удобен, когда нужно гарантировать, что все объекты в сессии будут прочитаны заново, например после выполнения массовых UPDATE или DELETE запросов через ядро, которые не синхронизируют состояние сессии.
Синтаксис
Session.expire_all()
Пример
Давайте создадим сессию, добавим объект,
затем вызовем expire_all и посмотрим,
как SQLAlchemy перезагрузит данные при
обращении к атрибуту:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1')
session.add(article)
session.commit()
print(article.title)
session.expire_all()
print(article.title)
Результат выполнения кода:
"article 1"
"article 1"
Внешне вывод не изменился, но после вызова
expire_all обращение к атрибуту
title вызвало новый SELECT-запрос
к базе данных.
Пример
Давайте убедимся, что после expire_all
объект действительно перечитывается из базы.
Изменим данные через ядро и посмотрим
на результат:
from sqlalchemy import create_engine, Integer, String, text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1')
session.add(article)
session.commit()
session.execute(text("UPDATE articles SET title = 'article 2'"))
session.expire_all()
print(article.title)
Результат выполнения кода:
"article 2"
Без вызова expire_all в переменной
article.title осталось бы старое
значение 'article 1', так как сессия
не знает об изменениях, сделанных в обход ORM.
Пример
Давайте посмотрим на SQL-запросы, которые
генерирует SQLAlchemy при вызове
expire_all. Включим вывод через
параметр echo:
from sqlalchemy import create_engine, Integer, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(Integer, primary_key=True)
title: Mapped[str] = mapped_column(String)
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
with Session(engine) as session:
article = Article(title='article 1')
session.add(article)
session.commit()
session.expire_all()
print(article.title)
Итоговый SQL запрос после вызова expire_all:
SELECT articles.id AS articles_id, articles.title AS articles_title
FROM articles
WHERE articles.id = ?