Vue d'ensemble
SQLAlchemy 2.0, publié le 27 janvier 2023, est une réécriture majeure de l'ORM. Le nouveau style déclaratif avec mapped_column(), le support natif de l'async et une API unifiée modernisent complètement le framework.
Fonctionnalités principales
Nouveau style déclaratif avec mapped_column()
Le nouveau système de mapping utilise Mapped[] et mapped_column() pour définir les colonnes de manière typée. Cela remplace l'ancien Column() et offre une meilleure intégration avec mypy.
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String
class Base(DeclarativeBase):
pass
class Utilisateur(Base):
__tablename__ = 'utilisateurs'
id: Mapped[int] = mapped_column(primary_key=True)
nom: Mapped[str] = mapped_column(String(100))
email: Mapped[str | None] = mapped_column(String(200))
# Le type Python détermine le type SQL et la nullabilité
# Mapped[str] -> NOT NULL, Mapped[str | None] -> NULLABLE
Support natif async
SQLAlchemy 2.0 intègre nativement le support asyncio via create_async_engine et AsyncSession, permettant d'utiliser l'ORM dans des applications asynchrones sans wrapper externe.
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from sqlalchemy import select
engine = create_async_engine('sqlite+aiosqlite:///app.db')
async_session = sessionmaker(engine, class_=AsyncSession)
async def get_utilisateurs():
async with async_session() as session:
result = await session.execute(
select(Utilisateur).where(Utilisateur.nom.like('%dupont%'))
)
return result.scalars().all()
API select() unifiée
L'ancienne API session.query() est remplacée par le style select() unifié. Toutes les requêtes passent désormais par session.execute(select(...)), offrant une API cohérente entre Core et ORM.
from sqlalchemy import select, func
from sqlalchemy.orm import Session
with Session(engine) as session:
# Ancien style (déprécié) : session.query(Utilisateur).filter(...)
# Nouveau style 2.0 :
stmt = (
select(Utilisateur)
.where(Utilisateur.email.isnot(None))
.order_by(Utilisateur.nom)
)
utilisateurs = session.execute(stmt).scalars().all()
# Agrégation
count = session.execute(
select(func.count()).select_from(Utilisateur)
).scalar()
