🔝 Retour au Sommaire
SQLAlchemy est une bibliothèque Python qui facilite l'interaction avec les bases de données relationnelles. C'est ce qu'on appelle un ORM (Object-Relational Mapping), c'est-à-dire un outil qui permet de manipuler des données de base de données comme si c'était des objets Python.
Sans SQLAlchemy, pour interagir avec une base de données, vous devriez écrire du code SQL brut :
# Sans SQLAlchemy (SQL brut)
cursor.execute("SELECT * FROM users WHERE age > 18")
results = cursor.fetchall() Avec SQLAlchemy, vous manipulez des objets Python naturellement :
# Avec SQLAlchemy (ORM)
users = session.query(User).filter(User.age > 18).all()Avantages principaux :
- Code Python plus lisible et maintenable
- Protection contre les injections SQL
- Compatibilité avec plusieurs bases de données (SQLite, PostgreSQL, MySQL, etc.)
- Validation automatique des données
- Gestion simplifiée des relations entre tables
Pour installer SQLAlchemy, utilisez pip :
pip install sqlalchemyPour suivre ce tutoriel avec SQLite (base de données simple intégrée à Python), aucune installation supplémentaire n'est nécessaire.
SQLAlchemy offre deux approches principales :
- SQLAlchemy Core : Niveau plus bas, proche du SQL mais avec Python
- SQLAlchemy ORM : Niveau plus haut, manipulation d'objets Python
Dans ce tutoriel, nous nous concentrerons sur l'ORM, qui est plus intuitif pour les débutants.
Le moteur est la connexion à votre base de données. C'est le point d'entrée de SQLAlchemy.
from sqlalchemy import create_engine
# Création d'une connexion à une base de données SQLite
# Le fichier 'ma_base.db' sera créé automatiquement
engine = create_engine('sqlite:///ma_base.db', echo=True)Paramètres importants :
echo=True: Affiche toutes les requêtes SQL générées (utile pour apprendre)echo=False: Mode production, n'affiche rien
Syntaxes de connexion courantes :
# SQLite (fichier local)
engine = create_engine('sqlite:///ma_base.db')
# SQLite (en mémoire, pour les tests)
engine = create_engine('sqlite:///:memory:')
# PostgreSQL
engine = create_engine('postgresql://user:password@localhost/ma_base')
# MySQL
engine = create_engine('mysql://user:password@localhost/ma_base')La session est votre espace de travail pour interagir avec la base de données. C'est comme un "panier" où vous placez vos modifications avant de les enregistrer définitivement.
from sqlalchemy.orm import sessionmaker
# Création d'une classe Session liée à notre moteur
Session = sessionmaker(bind=engine)
# Création d'une instance de session
session = Session()Concept important : La session garde en mémoire vos changements et les envoie à la base de données uniquement quand vous le décidez (avec commit()).
Pour définir nos tables, nous utilisons le système déclaratif de SQLAlchemy. Toutes nos classes de modèles hériteront d'une classe de base commune.
from sqlalchemy.orm import declarative_base
# Création de la classe de base
Base = declarative_base()Créons un modèle simple pour une table User :
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
# Configuration de base
Base = declarative_base()
engine = create_engine('sqlite:///users.db', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
# Définition du modèle User
class User(Base):
__tablename__ = 'users' # Nom de la table dans la base de données
# Définition des colonnes
id = Column(Integer, primary_key=True) # Clé primaire auto-incrémentée
nom = Column(String(50), nullable=False) # Chaîne de 50 caractères max, obligatoire
email = Column(String(100), unique=True) # Email unique
age = Column(Integer)
def __repr__(self):
# Méthode pour afficher l'objet de manière lisible
return f"<User(nom='{self.nom}', email='{self.email}', age={self.age})>"
# Création des tables dans la base de données
Base.metadata.create_all(engine)Explication détaillée :
__tablename__: Nom de la table en base de donnéesColumn: Définit une colonne avec son type et ses contraintesprimary_key=True: Identifiant unique de chaque lignenullable=False: Le champ est obligatoireunique=True: Chaque valeur doit être unique dans la table__repr__: Méthode spéciale pour afficher l'objet de façon lisible
SQLAlchemy offre de nombreux types de colonnes :
from sqlalchemy import Integer, String, Float, Boolean, DateTime, Text
class Exemple(Base):
__tablename__ = 'exemples'
id = Column(Integer, primary_key=True)
nom = Column(String(100)) # Texte court (limite de caractères)
description = Column(Text) # Texte long (sans limite)
prix = Column(Float) # Nombre décimal
en_stock = Column(Boolean) # True/False
date_creation = Column(DateTime) # Date et heurePour ajouter des données dans la base :
# Création d'un nouvel utilisateur
nouveau_user = User(nom="Alice Dupont", email="alice@example.com", age=28)
# Ajout à la session (préparation)
session.add(nouveau_user)
# Envoi à la base de données (sauvegarde définitive)
session.commit()
print(f"Utilisateur créé avec l'ID : {nouveau_user.id}")Étapes importantes :
- Créer un objet Python
- L'ajouter à la session avec
add() - Confirmer avec
commit()
Pour ajouter plusieurs enregistrements en une fois :
users = [
User(nom="Bob Martin", email="bob@example.com", age=35),
User(nom="Claire Petit", email="claire@example.com", age=42),
User(nom="David Leroux", email="david@example.com", age=29)
]
session.add_all(users)
session.commit() # Récupérer tous les utilisateurs
tous_les_users = session.query(User).all()
for user in tous_les_users:
print(user)# Récupérer l'utilisateur avec l'ID 1
user = session.get(User, 1)
print(user) # Utilisateurs de plus de 30 ans
users_30_plus = session.query(User).filter(User.age > 30).all()
# Utilisateur avec un email spécifique
user = session.query(User).filter(User.email == "alice@example.com").first()
# .first() retourne le premier résultat (ou None si aucun)# Nombre total d'utilisateurs
nombre_users = session.query(User).count()
print(f"Nombre d'utilisateurs : {nombre_users}") # Récupérer un utilisateur
user = session.query(User).filter(User.nom == "Alice Dupont").first()
# Modifier ses attributs
user.age = 29
user.email = "alice.dupont@example.com"
# Sauvegarder les changements
session.commit()SQLAlchemy détecte automatiquement les modifications et génère la requête SQL UPDATE appropriée.
# Récupérer un utilisateur
user = session.query(User).filter(User.nom == "Bob Martin").first()
# Supprimer de la session
session.delete(user)
# Confirmer la suppression
session.commit()Les transactions permettent de regrouper plusieurs opérations et de les annuler en cas d'erreur :
try:
# Plusieurs opérations
user1 = User(nom="Test1", email="test1@example.com", age=25)
user2 = User(nom="Test2", email="test2@example.com", age=30)
session.add(user1)
session.add(user2)
# Si tout se passe bien, on enregistre
session.commit()
except Exception as e:
# En cas d'erreur, on annule tout
session.rollback()
print(f"Erreur : {e}")
finally:
# Fermeture de la session
session.close()Concepts clés :
commit(): Valide toutes les modificationsrollback(): Annule toutes les modifications depuis le dernier commitclose(): Ferme la session
Au lieu de gérer manuellement l'ouverture/fermeture des sessions :
from contextlib import contextmanager
@contextmanager
def get_session():
session = Session()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
# Utilisation
with get_session() as session:
user = User(nom="Exemple", email="exemple@example.com", age=25)
session.add(user)
# La session est automatiquement fermée et committéedef creer_utilisateur(nom, email, age):
# Validations
if not nom or len(nom) < 2:
raise ValueError("Le nom doit contenir au moins 2 caractères")
if age < 0 or age > 150:
raise ValueError("L'âge doit être entre 0 et 150")
# Création
user = User(nom=nom, email=email, age=age)
session.add(user)
session.commit()
return userQuand vous travaillez avec des relations entre tables (que nous verrons dans le prochain chapitre), faites attention aux requêtes répétées. SQLAlchemy offre des mécanismes d'optimisation comme le "eager loading".
Voici un exemple complet qui met tout ensemble :
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
# Configuration
Base = declarative_base()
engine = create_engine('sqlite:///gestion_users.db', echo=False)
Session = sessionmaker(bind=engine)
# Modèle
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
nom = Column(String(50), nullable=False)
email = Column(String(100), unique=True, nullable=False)
age = Column(Integer)
def __repr__(self):
return f"<User(id={self.id}, nom='{self.nom}', email='{self.email}')>"
# Création des tables
Base.metadata.create_all(engine)
# Fonction pour ajouter un utilisateur
def ajouter_utilisateur(nom, email, age):
session = Session()
try:
user = User(nom=nom, email=email, age=age)
session.add(user)
session.commit()
print(f"✓ Utilisateur {nom} ajouté avec succès!")
return user
except Exception as e:
session.rollback()
print(f"✗ Erreur : {e}")
finally:
session.close()
# Fonction pour lister tous les utilisateurs
def lister_utilisateurs():
session = Session()
try:
users = session.query(User).all()
if users:
print("\n=== Liste des utilisateurs ===")
for user in users:
print(f"- {user.nom} ({user.email}) - {user.age} ans")
else:
print("Aucun utilisateur trouvé.")
finally:
session.close()
# Fonction pour rechercher un utilisateur par email
def rechercher_par_email(email):
session = Session()
try:
user = session.query(User).filter(User.email == email).first()
if user:
print(f"Utilisateur trouvé : {user}")
else:
print(f"Aucun utilisateur avec l'email {email}")
return user
finally:
session.close()
# Utilisation
if __name__ == "__main__":
# Ajout d'utilisateurs
ajouter_utilisateur("Marie Curie", "marie@science.com", 45)
ajouter_utilisateur("Albert Einstein", "albert@physics.com", 76)
ajouter_utilisateur("Ada Lovelace", "ada@coding.com", 36)
# Liste
lister_utilisateurs()
# Recherche
rechercher_par_email("marie@science.com")Configuration de base :
- Créer un
engine(connexion à la base) - Créer une
Session(espace de travail) - Définir une
Base(classe parente des modèles)
Définition d'un modèle :
- Hériter de
Base - Définir
__tablename__ - Créer des colonnes avec
Column() - Spécifier les types et contraintes
Opérations CRUD :
- Create :
session.add()puissession.commit() - Read :
session.query().filter().all()ou.first() - Update : Modifier l'objet puis
session.commit() - Delete :
session.delete()puissession.commit()
Sécurité :
- Toujours utiliser
try/exceptavecrollback() - Fermer les sessions avec
close() - SQLAlchemy protège automatiquement contre les injections SQL
Maintenant que vous maîtrisez les bases de SQLAlchemy, vous êtes prêt à explorer :
- Les relations entre tables (One-to-Many, Many-to-Many)
- Les requêtes plus complexes (jointures, agrégations)
- Les migrations de base de données
- L'intégration avec des frameworks web (FastAPI, Flask)
SQLAlchemy est un outil puissant qui simplifie grandement le travail avec les bases de données. Avec ces fondamentaux, vous pouvez déjà créer des applications qui persistent des données de manière fiable et maintenable.