Ответ
Ключевое различие заключается в том, что SQLAlchemy 2.0 вводит новый, полностью типизированный и унифицированный API (т.н. "2.0 style"), который стал стандартом. Версия 1.4 была переходной и поддерживала оба стиля (старый 1.x и новый 2.0) для обратной совместимости.
Основные отличия SQLAlchemy 2.0:
- Унифицированный Core API: Метод
session.query()был заменен наselect(), что унифицирует работу с Core и ORM. - Полная поддержка типизации: Введены
Mappedиmapped_columnдля явного объявления колонок модели, что обеспечивает полную поддержку статических анализаторов, таких как Mypy. - Нативная поддержка
asyncio: API для асинхронной работы был полностью переработан и стал более стабильным и интуитивным.
Сравнение синтаксиса:
-
Стиль 1.4 (и ранее):
from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(50)) # Запрос # users = session.query(User).filter_by(name='John').all() -
Стиль 2.0 (рекомендуемый):
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(50)) # Запрос # from sqlalchemy import select # statement = select(User).where(User.name == 'John') # users = session.scalars(statement).all()
Рекомендация: Для всех новых проектов следует использовать исключительно синтаксис SQLAlchemy 2.0.
Ответ 18+ 🔞
Да ты посмотри, какая хуйня творится! SQLAlchemy, блядь, выпустили версию 2.0, и там, сука, всё перевернули с ног на голову, но как бы по-хорошему. А версия 1.4 — это такой хитрожопый переходный мостик, где и старое работало, и новое уже можно было тыкать.
В чём, блядь, соль-то?
- API новый, универсальный. Раньше ты в ORM
session.query(User)писал, а в Coreselect(). Теперь, ёпта, вездеselect()! Красота, блядь, единообразие. - Типизация наше всё. Раньше колонки объявляли просто
Column(), а теперь надоMappedиmapped_columnписать. Зато твой Mypy не будет орать как резаный, всё проверит. Не "подозрение ебать чувствую", а уверенность, что код не развалится. - Асинхронность не кривая. В 2.0
asyncioподдержали по-взрослому, не то что раньше, где всё было через жопу и костыли.
Смотри, как раньше было и как теперь:
-
Старый стиль (1.4 и древнее):
from sqlalchemy import Column, Integer, String from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(50)) # Запрос # users = session.query(User).filter_by(name='John').all()Скучно, предсказуемо, типов никаких.
-
Новый стиль 2.0 (охуенный):
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class User(Base): __tablename__ = 'users' id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(50)) # Запрос # from sqlalchemy import select # statement = select(User).where(User.name == 'John') # users = session.scalars(statement).all()Красота, блядь! Всё явно, типы на месте, код читается как книга. Ну, как книга про Герасима и Муму, только с хэппи-эндом.
Итог, ёпта: Если новый проект затеваешь — даже не думай, блядь, бери сразу синтаксис SQLAlchemy 2.0. Не будь тем самым Герасимом, который топиит свою же собаку, используя устаревший API. Иди в ногу со временем, в рот меня чих-пых!