Ответ
Декларативный маппинг — это основной и наиболее современный способ определения моделей в SQLAlchemy. Он позволяет описать таблицы базы данных и их взаимосвязи с помощью обычных Python-классов, объединяя метаданные таблицы и логику модели в одном месте.
Этот подход противопоставляется более старому, классическому маппингу, где структура таблицы и класс определялись раздельно.
Ключевые компоненты:
declarative_base(): Фабричная функция, которая создает базовый класс для всех моделей.__tablename__: Атрибут класса, указывающий имя таблицы в БД.Column: Объект, описывающий колонку таблицы, ее тип и ограничения.relationship: Определяет связь между моделями (один-ко-многим, многие-ко-многим).
Пример: модели User и Post со связью "один-ко-многим"
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker, declarative_base
# 1. Создание базового класса для моделей
Base = declarative_base()
# 2. Определение модели User
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50), nullable=False)
# Связь: у одного пользователя может быть много постов
posts = relationship("Post", back_populates="author")
# 3. Определение модели Post
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String(100), nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
# Обратная связь: у поста есть один автор
author = relationship("User", back_populates="posts")
# Использование:
# engine = create_engine('sqlite:///:memory:')
# Base.metadata.create_all(engine)
Преимущества декларативного подхода:
- Читаемость и поддержка: Код становится интуитивно понятным, так как структура таблицы и ее программное представление находятся в одном классе.
- Простота: Значительно сокращает количество шаблонного кода по сравнению с классическим подходом.
- Интеграция: Является стандартом де-факто и отлично интегрируется с инструментами миграций, такими как Alembic.
Ответ 18+ 🔞
А, ну так вот, слушай, про этот ваш декларативный маппинг в SQLAlchemy. Это ж, блядь, как будто взяли и наконец-то по-человечески сделали, а не как раньше, когда мозги выносило на раз-два.
Раньше-то, классический маппинг, это был пиздец, блядь. Отдельно таблицу описываешь, как будто в каменном веке, отдельно класс пишешь, а потом их ещё склеить надо. А тут — ёпта, красота! Всё в одном месте, в одном классе. И таблица, и модель, и логика — всё, сука, вместе. Как будто тебе дали конструктор "Лего" вместо кучи разрозненных палок и говна.
Вот смотри, из чего этот конструктор состоит, главные детальки:
declarative_base(): Это типа волшебная палочка, которая создаёт тебе базовый класс. От него все твои будущие модели будут наследоваться. Без него нихуя не начнётся.__tablename__: Это ты пишешь прямо в классе, как таблицу в базе назвать. Без этого SQLAlchemy начнёт выёбываться и придумывать имя сама, а это обычно пиздец как криво получается.Column: Ну это, блядь, столбец таблицы. Тут ты указываешь, что это за хуйня:Integer,String, и какие ограничения:primary_key=True,nullable=False(то есть, чтоб не пустое было, а то потом охуеешь искать баг).relationship: А вот это уже магия поинтереснее. Это связь между моделями. Типа "один пользователь — много постов". Без неё ты будешь вручнуюJOIN-ы писать, как лох.
Ладно, хватит болтать, вот тебе живой пример: Пользователь и его посты (один ко многим).
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker, declarative_base
# 1. Тыкаем волшебную палочку — создаём базовый класс
Base = declarative_base()
# 2. Делаем модель Юзера. Всё в одном классе, блядь, удобно же!
class User(Base):
__tablename__ = 'users' # Название таблицы в базе
id = Column(Integer, primary_key=True) # ID, главный ключ, ёпта
name = Column(String(50), nullable=False) # Имя, и чтоб не пустое, сука!
# А вот и магия связи! Говорим: "У этого пользователя есть посты".
# "Post" — это название класса модели поста.
# back_populates="author" — это чтобы из поста тоже можно было до юзера достучаться.
posts = relationship("Post", back_populates="author")
# 3. Теперь модель Поста
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
title = Column(String(100), nullable=False)
user_id = Column(Integer, ForeignKey('users.id')) # Ссылаемся на юзера
# Обратная связь. Говорим: "У этого поста есть автор".
# Ссылаемся на класс "User", а конкретно на его атрибут "posts".
author = relationship("User", back_populates="posts")
# Ну и как это использовать, блядь:
# engine = create_engine('sqlite:///:memory:') # Создаём движок для базы
# Base.metadata.create_all(engine) # Эта команда, ёпта, создаст все таблицы в базе по нашим моделям. Красота!
И в чём же, блядь, охуенность этого подхода?
- Читаемость заебись: Открыл один файл, один класс — и сразу видно, какая таблица, какие поля, какие связи. Не надо прыгать между пятью разными местами, ебать твою мать.
- Простота, блять: Раньше кода было как говна за баней, а теперь — чисто, аккуратно, по делу. Меньше писанины — меньше ошибок.
- Всё дружит: Этот подход — как родной для всех современных инструментов. Тот же Alembic для миграций на него смотрит и говорит: "О, бля, знакомый, сейчас всё автоматически нагенерирую". И правда нагенерирует, без твоих кривых рук.
В общем, если ты до сих пор юзаешь что-то другое — ты просто, извини, еблан. Всё, точка.