Ответ
SQLAlchemy ORM — это инструмент в Python для взаимодействия с реляционными базами данных с использованием объектно-ориентированного подхода. Он позволяет абстрагироваться от написания SQL-запросов, представляя таблицы как классы, а строки в них — как экземпляры этих классов.
Ключевые компоненты:
- Engine: Объект, управляющий пулом соединений с базой данных. Создается один раз для всего приложения.
- Декларативное объявление моделей: Классы Python, наследуемые от
declarative_base(), которые сопоставляются с таблицами в БД. - Session: Основной интерфейс для работы с ORM. Сессия управляет состоянием объектов (транзакциями), отслеживает изменения и формирует SQL-запросы.
Базовый пример (CRUD):
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
# 1. Определение модели
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
# 2. Создание Engine и Session
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine) # Создание таблицы
Session = sessionmaker(bind=engine)
session = Session()
# 3. Создание и добавление объекта (Create)
new_user = User(name='Alice')
session.add(new_user)
session.commit()
# 4. Запрос объекта (Read)
# Стиль 1.x (устаревший, но распространенный)
user = session.query(User).filter_by(name='Alice').first()
print(f"Найден пользователь: {user.name}")
# 5. Обновление (Update)
user.name = 'Alice Smith'
session.commit()
# 6. Удаление (Delete)
session.delete(user)
session.commit()
Важные аспекты:
- Управление транзакциями: Все изменения внутри сессии накапливаются и отправляются в БД только после вызова
session.commit(). В случае ошибкиsession.rollback()отменяет изменения. - Отношения: SQLAlchemy позволяет легко определять связи между моделями (
one-to-one,one-to-many,many-to-many) с помощьюrelationship(). - Оптимизация запросов: Для предотвращения проблемы "N+1" используются стратегии немедленной загрузки связанных данных, например,
joinedload()илиselectinload().
Ответ 18+ 🔞
А, SQLAlchemy, блядь! Ну, это такая штука, которая позволяет тебе не писать SQL вручную, а работать с базой данных как с обычными питоновскими объектами. Представь, что таблица в базе — это класс, а каждая строчка в ней — экземпляр этого класса. Красота, да? Хули там париться с SELECT * FROM users WHERE id = 1, когда можно просто session.query(User).get(1).
Из чего эта махина состоит, на самом деле:
- Engine (Движок): Это, типа, сердце всей системы. Один такой объект на всё приложение, он отвечает за подключение к базе. Создал один раз — и забыл, как страшный сон.
- Модели (Объявление): Берёшь обычный питоновский класс, наследуешь его от какой-то волшебной
Base, и вуаля — он теперь умеет превращаться в таблицу. Колонки объявляешь прямо как атрибуты класса. Прямо как в сказке, только без Буратино. - Session (Сессия): Вот это, блядь, самое важное. Сессия — это твой личный переводчик и курьер. Через неё ты общаешься с базой. Она следит за всеми твоими объектами, запоминает, что ты их поменял, и когда ты скажешь "всё, пиздуй" (
session.commit()), она аккуратно упаковывает все изменения и отправляет их в базу одной пачкой. А если что-то пошло не так — откатывает всё нахуй (session.rollback()).
Смотри, как это выглядит на практике, ёпта:
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
# 1. Создаём базу для наших моделей. Это как чертёж.
Base = declarative_base()
# Вот наша модель — пользователь. Просто класс, блядь.
class User(Base):
__tablename__ = 'users' # Имя таблицы в базе
id = Column(Integer, primary_key=True) # Главный ключ, нулевой пациент
name = Column(String(50)) # Имя, строка на 50 символов
# 2. Заводим движок и сессию. Движок — на SQLite в памяти (для примера).
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine) # Эта команда создаёт таблицы по нашим чертежам. Магия, блядь!
Session = sessionmaker(bind=engine) # Фабрика сессий, привязанная к движку
session = Session() # Вот она, родная, наша сессия для работы
# 3. СОЗДАНИЕ (Create). Делаем нового юзера и пихаем его в сессию.
new_user = User(name='Алиса')
session.add(new_user) # Сессия: "Ага, запомнила, новый объект"
session.commit() # Сессия: "Всё, понеслась, записываю в базу!"
# 4. ЧТЕНИЕ (Read). Старый добрый способ (1.x стиль), его ещё дохуя где используют.
user = session.query(User).filter_by(name='Алиса').first() # "Дай мне первого юзера с именем 'Алиса'"
print(f"Нашли какого-то: {user.name}")
# 5. ОБНОВЛЕНИЕ (Update). Меняем имя прямо у объекта.
user.name = 'Алиса Смит'
session.commit() # Сессия видит, что объект грязный, и обновляет его в базе.
# 6. УДАЛЕНИЕ (Delete). Прощай, Алиса.
session.delete(user)
session.commit() # И след простыл.
На что ещё обратить взор, чтобы не облажаться:
- Транзакции: Пока не сказал
commit()— нихуя не произошло в базе. Всё висит в памяти сессии. Сказалcommit()— изменения улетели. Накосячил —rollback(), и все твои грехи как рукой сняло. Это, блядь, святое. - Связи (Relationships): Это когда у тебя таблицы связаны друг с другом (например, у пользователя много постов). SQLAlchemy позволяет описать это парой строчек с помощью
relationship(). Очень мощная хуйня, но если использовать бездумно — получишь проблему N+1 и будешь потом ебаться с оптимизацией. - Жадная загрузка (Eager Loading): Вот та самая защита от проблемы N+1. Чтобы не делать отдельный запрос в базу за постами каждого пользователя (представь, если их 1000), можно сразу в одном запросе всё подгрузить. Для этого есть
joinedload()илиselectinload(). Игнорируешь это — твоё приложение будет работать, как черепаха в сиропе, а ты будешь чесать репу, не понимая, в чём дело.
Вот, в общих чертах, и вся магия. Выглядит просто, но под капотом там, блядь, целый космический корабль. Главное — не забывай про commit() и rollback(), а то наделаешь делов.