РЕПЕТИТОР математика физика информатика
Для школьников и студентов. Подтягивание пробелов. ЦЭ, ЦТ, ОГЭ, ЕГЭ.
Идет набор на ЛЕТО. Жмите для подробностей:)
524 of 711 menu

Функция with_loader_criteria

Функция with_loader_criteria добавляет дополнительное условие фильтрации к сущностям, которые загружаются через связь. Первым параметром функция принимает класс сущности, к которой нужно применить критерий. Вторым параметром передается SQL-выражение с условием. Третий необязательный параметр include_aliases управляет применением критерия к алиасам сущности.

Функция применяется внутри опций загрузки, таких как selectinload, joinedload или subqueryload, и позволяет отфильтровать загружаемые связанные объекты без изменения основного запроса.

Синтаксис

with_loader_criteria(entity, criterion, [include_aliases])

Пример

Давайте создадим две связанные модели и загрузим только активные статьи пользователя. Для этого используем with_loader_criteria вместе с selectinload:

from sqlalchemy import create_engine, ForeignKey, select from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session from sqlalchemy.orm import selectinload, with_loader_criteria class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] articles: Mapped[list['Article']] = relationship(back_populates='user') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] status: Mapped[str] user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) user: Mapped['User'] = relationship(back_populates='articles') engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: user = User(id=1, title='user') user.articles = [ Article(id=1, title='article 1', status='active'), Article(id=2, title='article 2', status='draft'), Article(id=3, title='article 3', status='active'), ] session.add(user) session.commit() stmt = ( select(User) .options( selectinload(User.articles).options( with_loader_criteria(Article, Article.status == 'active') ) ) ) res = session.scalars(stmt).unique().all() for u in res: print([a.title for a in u.articles])

Результат выполнения кода:

<+python+> ['article 1', 'article 3'] <-python+>

Пример

Давайте применим критерий к самому классу Article через параметр with_loader_criteria на уровне всего запроса. В этом случае условие затронет все загрузки этой сущности:

<+python+> from sqlalchemy import create_engine, ForeignKey, select from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session from sqlalchemy.orm import selectinload, with_loader_criteria class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] articles: Mapped[list['Article']] = relationship(back_populates='user') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] status: Mapped[str] user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) user: Mapped['User'] = relationship(back_populates='articles') engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: user = User(id=1, title='user') user.articles = [ Article(id=1, title='article 1', status='active'), Article(id=2, title='article 2', status='draft'), Article(id=3, title='article 3', status='active'), ] session.add(user) session.commit() stmt = ( select(User) .options( selectinload(User.articles), with_loader_criteria(Article, Article.status == 'active'), ) ) res = session.scalars(stmt).unique().all() for u in res: print([a.title for a in u.articles]) <-python+>

Результат выполнения кода:

<+python+> ['article 1', 'article 3'] <-python+>

Пример

Давайте используем with_loader_criteria вместе с joinedload и лямбда-выражением для критерия. Лямбда позволяет сослаться на класс сущности без явного импорта:

<+python+> from sqlalchemy import create_engine, ForeignKey, select from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session from sqlalchemy.orm import joinedload, with_loader_criteria class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] articles: Mapped[list['Article']] = relationship(back_populates='user') class Article(Base): __tablename__ = 'articles' id: Mapped[int] = mapped_column(primary_key=True) title: Mapped[str] status: Mapped[str] num: Mapped[int] user_id: Mapped[int] = mapped_column(ForeignKey('users.id')) user: Mapped['User'] = relationship(back_populates='articles') engine = create_engine('sqlite:///:memory:') Base.metadata.create_all(engine) with Session(engine) as session: user = User(id=1, title='user') user.articles = [ Article(id=1, title='article 1', status='active', num=1), Article(id=2, title='article 2', status='active', num=2), Article(id=3, title='article 3', status='active', num=3), ] session.add(user) session.commit() stmt = ( select(User) .options( joinedload(User.articles).options( with_loader_criteria(Article, lambda cls: cls.num > 1) ) ) ) res = session.scalars(stmt).unique().all() for u in res: print([a.title for a in u.articles]) <-python+>

Результат выполнения кода:

<+python+> ['article 2', 'article 3'] <-python+>

Смотрите также

  • функцию selectinload,
    которая загружает связи отдельным запросом
  • функцию joinedload,
    которая загружает связи через JOIN
  • функцию subqueryload,
    которая загружает связи через подзапрос
  • функцию with_expression,
    которая добавляет SQL-выражение к загружаемому объекту
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить