Функция defaultload
Функция defaultload задает стратегию загрузки
связанных объектов, которая применяется к связи
только в рамках текущего запроса. Первым параметром
функция принимает атрибут связи, для которого нужно
применить настройку. Вторым параметром передается
сама стратегия загрузки, например joinedload,
selectinload, lazyload или noload.
В отличие от настройки связи через параметр lazy
в relationship, функция defaultload меняет
поведение загрузки только для одного конкретного
запроса и не затрагивает глобальные настройки модели.
Синтаксис
from sqlalchemy.orm import defaultload
defaultload(attribute, strategy)
Пример
Давайте создадим модели статьи и пользователя,
а затем применим defaultload для загрузки
связи через joinedload:
from sqlalchemy import ForeignKey, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
articles: Mapped[list['Article']] = relationship(back_populates='user')
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
text: Mapped[str] = mapped_column(Text)
status: Mapped[str] = mapped_column(String(20))
num: Mapped[int]
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
user: Mapped['User'] = relationship(back_populates='articles')
Теперь выполним запрос с применением defaultload:
from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session, joinedload, defaultload
from models import Base, User, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(name='user')
article = Article(
title='article',
text='text',
status='draft',
num=1,
user=user,
)
session.add_all([user, article])
session.commit()
stmt = (
select(Article)
.options(defaultload(Article.user).joinedload(User.articles))
)
res = session.scalars(stmt).all()
for item in res:
print(item.title, item.user.name)
Результат выполнения кода:
"article user"
Пример
Давайте применим defaultload для отключения
загрузки связи через noload:
from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session, noload, defaultload
from models import Base, User, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(name='user')
article = Article(
title='article',
text='text',
status='draft',
num=1,
user=user,
)
session.add_all([user, article])
session.commit()
session.expunge_all()
stmt = (
select(Article)
.options(defaultload(Article.user).noload())
)
res = session.scalars(stmt).all()
for item in res:
print(item.title, item.user)
Результат выполнения кода:
"article None"
Пример
Давайте применим defaultload для загрузки
связи через selectinload:
from sqlalchemy import create_engine, select
from sqlalchemy.orm import Session, selectinload, defaultload
from models import Base, User, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
user = User(name='user')
article = Article(
title='article',
text='text',
status='draft',
num=1,
user=user,
)
session.add_all([user, article])
session.commit()
session.expunge_all()
stmt = (
select(User)
.options(defaultload(User.articles).selectinload(Article.user))
)
res = session.scalars(stmt).all()
for item in res:
print(item.name, len(item.articles))
Результат выполнения кода:
"user 1"
Смотрите также
-
функцию
joinedload,
которая загружает связь через JOIN -
функцию
selectinload,
которая загружает связь отдельным SELECT IN запросом -
функцию
noload,
которая отключает загрузку связи -
функцию
lazyload,
которая задает ленивую загрузку связи