Ответ
В 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 тебя не поймёт, и будет тебе пиздец, а не запрос. Используй только то, что есть в документации, и всё будет, как по маслу, в рот меня чих-пых!