Класс hybrid_method
Класс hybrid_method создает гибридный метод,
который можно вызывать как обычный метод у экземпляра
модели и одновременно использовать как SQL-выражение
в запросах. Первым параметром декоратор принимает
функцию, внутри которой первый аргумент cls
представляет класс или экземпляр, а остальные
аргументы - параметры метода.
Синтаксис
from sqlalchemy.ext.hybrid import hybrid_method
class Model(Base):
@hybrid_method
def method_name(self, arg):
return expression
Пример
Давайте создадим модель Article с гибридным
методом is_longer_than, который проверяет
длину заголовка:
from sqlalchemy import create_engine, String
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.ext.hybrid import hybrid_method
class Base(DeclarativeBase):
pass
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(String(500))
@hybrid_method
def is_longer_than(self, length):
return len(self.title) > length
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(title='article', text='text'))
session.add(Article(title='very long article', text='text'))
session.commit()
article = session.get(Article, 1)
print(article.is_longer_than(5))
Результат выполнения кода:
False
Пример
Теперь используем гибридный метод внутри SQL-запроса
через select:
from sqlalchemy import create_engine, String, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.ext.hybrid import hybrid_method
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
@hybrid_method
def is_longer_than(self, length):
return len(self.title) > length
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(title='article', text='text'))
session.add(Article(title='very long article', text='text'))
session.commit()
stmt = select(Article).where(Article.is_longer_than(10))
res = session.scalars(stmt).all()
for article in res:
print(article.title)
Результат выполнения кода:
['very long article']
Пример
Гибридный метод может принимать несколько аргументов.
Создадим метод has_status, проверяющий
статус и числовое значение:
from sqlalchemy import create_engine, String, Integer, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
from sqlalchemy.ext.hybrid import hybrid_method
class Base(DeclarativeBase):
pass
class Article(Base):
__tablename__ = 'articles'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(100))
status: Mapped[str] = mapped_column(String(20))
num: Mapped[int] = mapped_column(Integer)
@hybrid_method
def has_status(self, status, min_num):
return (self.status == status) & (self.num >= min_num)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
with Session(engine) as session:
session.add(Article(title='article 1', status='active', num=5))
session.add(Article(title='article 2', status='active', num=15))
session.add(Article(title='article 3', status='draft', num=25))
session.commit()
stmt = select(Article).where(Article.has_status('active', 10))
res = session.scalars(stmt).all()
for article in res:
print(article.title)
Результат выполнения кода:
['article 2']
Смотрите также
-
класс
relationship,
который настраивает связи между моделями -
класс
backref,
который создает обратную ссылку в связи -
класс
foreign,
который указывает внешний ключ связи -
класс
selectinload,
который выполняет жадную загрузку связей