Метод from_self
Метод from_self класса Query
превращает уже построенный запрос в подзапрос
и возвращает новый объект Query,
который выбирает данные из этого подзапроса.
Это позволяет применять фильтры, сортировку
или ограничения к результату исходного запроса,
а не к исходной таблице. Первым параметром
можно передать сущности для выборки, а также
дополнительные опции, например filter
или order_by.
Синтаксис
from_self(*entities)
Пример
Давайте создадим модель Article
и посмотрим, как from_self
оборачивает запрос в подзапрос:
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str]
text: Mapped[str]
status: Mapped[str]
num: Mapped[int]
Теперь выполним запрос с from_self
и выведем полученные заголовки:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='new', num=10),
Article(title='article 2', text='text 2', status='new', num=20),
Article(title='article 3', text='text 3', status='old', num=30),
])
session.commit()
res = session.query(Article).from_self().all()
for article in res:
print(article.title)
Результат выполнения кода:
"article 1"
"article 2"
"article 3"
Пример
Давайте применим фильтр к результату
исходного запроса через from_self:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='new', num=10),
Article(title='article 2', text='text 2', status='new', num=20),
Article(title='article 3', text='text 3', status='old', num=30),
])
session.commit()
res = session.query(Article).filter(
Article.status == 'new'
).from_self().filter(
Article.num > 15
).all()
for article in res:
print(article.title)
Результат выполнения кода:
"article 2"
Пример
Давайте отсортируем результат подзапроса
по убыванию поля num:
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from models import Base, Article
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add_all([
Article(title='article 1', text='text 1', status='new', num=10),
Article(title='article 2', text='text 2', status='new', num=20),
Article(title='article 3', text='text 3', status='old', num=30),
])
session.commit()
res = session.query(Article).from_self().order_by(
Article.num.desc()
).all()
for article in res:
print(article.title, article.num)
Результат выполнения кода:
"article 3 30"
"article 2 20"
"article 1 10"
Итоговый SQL запрос:
SELECT anon_1.articles_id AS anon_1_articles_id,
anon_1.articles_title AS anon_1_articles_title,
anon_1.articles_text AS anon_1_articles_text,
anon_1.articles_status AS anon_1_articles_status,
anon_1.articles_num AS anon_1_articles_num
FROM (SELECT articles.id AS articles_id,
articles.title AS articles_title,
articles.text AS articles_text,
articles.status AS articles_status,
articles.num AS articles_num
FROM articles) AS anon_1
ORDER BY anon_1.articles_num DESC