Для чего используется объект func в SQLAlchemy?

Ответ

В SQLAlchemy func — это специальный объект-генератор, который предоставляет доступ к SQL-функциям (агрегатным, строковым, математическим и др.) непосредственно из Python-кода.

Это позволяет конструировать сложные запросы, не прибегая к написанию "сырого" SQL, сохраняя при этом все преимущества ORM: переносимость между разными СУБД и интеграцию с моделями данных.

Основные группы функций

  • Агрегатные: func.count(), func.sum(), func.avg(), func.max().
  • Строковые: func.lower(), func.concat(), func.substring().
  • Даты и времени: func.now(), func.date().
  • Специфичные для СУБД: func.json_build_object() (PostgreSQL) и другие.

Пример использования (синтаксис SQLAlchemy 2.0)

Предположим, у нас есть модель User:

from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase

class Base(DeclarativeBase): pass

class User(Base):
    __tablename__ = 'users'
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    visit_count: Mapped[int]

Теперь мы можем использовать func в запросах:

from sqlalchemy import select, func
from sqlalchemy.orm import Session

# ... (engine и session настроены)

with Session(engine) as session:
    # 1. Подсчет всех пользователей
    count_stmt = select(func.count(User.id))
    user_count = session.execute(count_stmt).scalar_one()
    # SQL: SELECT count(users.id) FROM users

    # 2. Поиск пользователя с именем в нижнем регистре
    lower_name_stmt = select(User).where(func.lower(User.name) == "john")
    # SQL: SELECT ... FROM users WHERE lower(users.name) = 'john'

    # 3. Суммирование значений по полю
    total_visits_stmt = select(func.sum(User.visit_count))
    total_visits = session.execute(total_visits_stmt).scalar()
    # SQL: SELECT sum(users.visit_count) FROM users

Ответ 18+ 🔞

А, ну вот, блядь, смотри, сейчас объясню про эту штуку func в SQLAlchemy, чтобы ты не пиздел, что не понимаешь. Это же, ёпта, просто генератор, который даёт тебе доступ к SQL-функциям прямо из питона, как будто ты их сам придумал!

То есть, вместо того чтобы писать сырой SQL и потом охуевать, почему он не работает на другой базе, ты просто вызываешь func.count() или func.sum(), и ORM сама, хитрая жопа, переведёт это в нужный диалект — PostgreSQL, MySQL, SQLite, да хоть в наскальную живопись! Всё ради переносимости, блядь, и чтобы с твоими моделями не было конфликтов.

Какие бывают, нахуй

  • Агрегатные — те, что всё суммируют и считают: func.count(), func.sum(), func.avg(), func.max().
  • Строковые — для текстового извращения: func.lower(), func.concat(), func.substring().
  • Даты и времени — чтобы не запутаться, когда что произошло: func.now(), func.date().
  • Специфичные для СУБД — вот тут уже начинается магия, типа func.json_build_object() для PostgreSQL. Если используешь такое — готовься, что на SQLite это может не взлететь, пиздец.

Пример, чтобы не быть мудаком

Допустим, у тебя есть модель User, простая, как три копейки:

from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase

class Base(DeclarativeBase): pass

class User(Base):
    __tablename__ = 'users'
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    visit_count: Mapped[int]

И вот ты такой сидишь и думаешь: «Как бы мне посчитать этих пользователей, не выходя в консоль базы?». А вот так, блядь!

from sqlalchemy import select, func
from sqlalchemy.orm import Session

# ... (движок и сессия уже настроены, надеюсь)

with Session(engine) as session:
    # 1. Считаем всех юзеров, чтобы понять, насколько мы одиноки
    count_stmt = select(func.count(User.id))
    user_count = session.execute(count_stmt).scalar_one()
    # На выходе SQL: SELECT count(users.id) FROM users

    # 2. Ищем Джона, но вдруг он записался как «JoHn»? Приводим к нижнему регистру, ёба!
    lower_name_stmt = select(User).where(func.lower(User.name) == "john")
    # SQL: SELECT ... FROM users WHERE lower(users.name) = 'john'

    # 3. Суммируем все визиты — сколько раз нас вообще посещали, блядь
    total_visits_stmt = select(func.sum(User.visit_count))
    total_visits = session.execute(total_visits_stmt).scalar()
    # SQL: SELECT sum(users.visit_count) FROM users

Вот и вся магия, никакого шаманства. Главное — не начинай выдумывать свои функции, типа func.наебал_систему(), потому что SQLAlchemy тебя не поймёт, и будет тебе пиздец, а не запрос. Используй только то, что есть в документации, и всё будет, как по маслу, в рот меня чих-пых!