Flask-SQLAlchemy et Flask-Migrate : Le Guide de l’ORM

Lorsque l’on développe une application Flask, le choix de la gestion des données est crucial.
Pour transformer vos objets Python en tables de base de données sans écrire une seule ligne de SQL, le duo Flask-SQLAlchemy et Flask-Migrate est l’outil standard de l’écosystème.

1. Flask-SQLAlchemy : La puissance de l’ORM

Flask-SQLAlchemy simplifie l’utilisation d’SQLAlchemy. Un ORM (Object Relational Mapper) permet d’interagir avec votre base de données en manipulant des classes Python.

Pourquoi l’adopter ?

  • Abstraction : Plus besoin de jongler avec des requêtes SQL complexes.
  • Flexibilité : Changez de moteur de base de données (SQLite vers PostgreSQL) avec une simple ligne de configuration.
  • Intégration : Conçu spécifiquement pour s’intégrer dans le cycle de vie d’une application Flask.

2. Flask-SQLAlchemy et Flask-Migrate : Explication et Utilisation

Lorsque l’on développe une application Flask qui nécessite une base de données, il est important de choisir une bibliothèque pour interagir avec cette base et pour gérer les évolutions du schéma.
Flask-SQLAlchemy et Flask-Migrate sont deux extensions essentielles pour cela.
Avec Flask, la gestion des migrations de base de données se fait généralement avec Flask-Migrate, une extension basée sur Alembic.
Elle permet de suivre et d’appliquer les modifications du schéma de la base de données sans perdre les données existantes.

3. Flask-SQLAlchemy : Gestion de la Base de Données

📌 Qu’est-ce que Flask-SQLAlchemy ?

Flask-SQLAlchemy est une extension qui simplifie l’utilisation d’SQLAlchemy dans une application Flask.

SQLAlchemy est un ORM (Object Relational Mapper) puissant qui permet d’interagir avec une base de données en utilisant des objets Python au lieu d’écrire des requêtes SQL brutes.

🚀 Pourquoi utiliser Flask-SQLAlchemy ?

  • Facilite la gestion des bases de données en Flask.
  • Permet d’écrire des requêtes SQL de manière plus intuitive en Python.
  • Prend en charge plusieurs types de bases de données (SQLite, PostgreSQL, MySQL, etc.).
  • Fournit un système de migration facile à utiliser avec Flask-Migrate.

🔧 Exemple de configuration de Flask-SQLAlchemy

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'  # Connexion à SQLite
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)  # Création de l'instance SQLAlchemy

# Définition d'un modèle pour une table "users"
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

# Création de la base de données (uniquement lors de la première exécution)
with app.app_context():
    db.create_all()
Python

4. Flask-Migrate : Gestion des Migrations

📌 Qu’est-ce que Flask-Migrate ?

Flask-Migrate est une extension qui permet de gérer les migrations de base de données en SQLAlchemy avec Alembic.
Une migration permet d’apporter des modifications à la structure de la base de données (ajout de colonnes, suppression de tables, modification de types de données, etc.) sans perdre les données existantes.

🚀 Pourquoi utiliser Flask-Migrate ?

– Permet d’appliquer des changements sur la base de données de manière progressive. – Facilite la gestion des versions du schéma de base de données. – Évite d’avoir à supprimer et recréer la base de données à chaque modification. —

Pour faire simple, Flask-Migrate (qui est une surcouche de l’outil Alembic) est l’équivalent de Git, mais pour le schéma de votre base de données.

Au lieu de modifier votre base de données à la main avec des requêtes SQL (ALTER TABLE, CREATE TABLE) — ce qui est dangereux et intraçable en production —, vous modifiez vos classes Python. Flask-Migrate se charge ensuite de calculer la différence (« diff ») entre votre code et la base de données, et de générer un script pour appliquer ces changements proprement.

📌 Étapes pour utiliser `flask db migrate`

  1. Voici comment fonctionne la migration avec Flask :
    • Installation de Flask-Migrate
    • Si ce n’est pas déjà fait, installez Flask-Migrate et SQLAlchemy : « bash pip install flask-migrate flask-sqlalchemy « `
    • Initialisation du projet
    • Il faut d’abord lier Flask, votre ORM (SQLAlchemy) et l’outil de migration :
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'  # Ou autre SGBD (PostgreSQL, MySQL, etc.)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
migrate = Migrate(app, db)  # Intégration avec Flask-Migrate

# Définition d’un modèle
class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    completed = db.Column(db.Boolean, default=False)

if __name__ == '__main__':
    app.run(debug=True)
Python

Initialisation de Flask-Migrate


(À ne faire qu’une seule fois par projet)

C’est l’équivalent de git init.

Bash
flask db init
Bash

👉 Cela crée un dossier migrations/ à la racine de votre projet qui contiendra tout l’historique de votre base de données.


Générer une migration


L’équivalent d’un git commit.

Imaginons que vous ajoutiez une colonne due_date à votre classe Task. Pour que la base de données soit au courant de ce changement de schéma, vous lancez :

Bash
flask db migrate -m "Ajout du modèle Task"

👉 Flask-Migrate analyse vos modèles Python, voit qu’il y a une différence avec la base actuelle, et génère un script Python dans le dossier migrations/versions/. À ce stade, la base de données n’est pas encore modifiée.


Appliquer la migration


L’équivalent d’un déploiement en production.

Pour exécuter le script généré à l’étape précédente et altérer physiquement le schéma de la base de données, on utilise :

Bash
flask db upgrade

👉 Cela exécute le script de migration et met à jour la base.


Gérer les modifications du modèle


Si vous modifiez un modèle (ex: ajouter une colonne `due_date` à `Task`) :

class Task(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    completed = db.Column(db.Boolean, default=False)
    due_date = db.Column(db.DateTime)  # Nouvelle colonne
Python

Exécutez les migrations :

Bash
flask db migrate -m "Ajout de due_date à Task"
flask db upgrade

Rollback en cas d’erreur :Optionnel.

Si la modification casse quelque chose ou que vous souhaitez revenir à l’état précédent du schéma, vous pouvez annuler la dernière migration :

Bash
 flask db downgrade

🛠 Commandes utiles

5. Résumé des commandes

Commande Description
flask db init Initialise le dossier `migrations`
flask db migrate -m « Message » Génère un fichier de migration basé sur les modifications du modèle
flask db upgrade Applique la migration à la base de données
flask db downgrade Annule la dernière migration
flask db history Affiche l’historique des migrations
flask db current Montre la version actuelle appliquée

6. Exemples d’utilisation

Ajout d’une colonne dans un modèle existant
Si l’on souhaite ajouter une nouvelle colonne age au modèle User, il suffit de :

Modifier le modèle Python :

class User(db.Model):
       id = db.Column(db.Integer, primary_key=True)
       username = db.Column(db.String(80), unique=True, nullable=False)
       email = db.Column(db.String(120), unique=True, nullable=False)
       age = db.Column(db.Integer, nullable=True)  # Nouvelle colonne
Python

Générer une nouvelle migration :

Bash
 flask db migrate -m "Ajout de la colonne age à User"

Appliquer la migration :

Bash
flask db upgrade

6. Résumé

Outil Rôle
Flask-SQLAlchemy Gère la connexion et l’interaction avec la base de données via un ORM
Flask-Migrate Permet d’appliquer des modifications au schéma de la base sans perdre de données

7. Modéliser les relations entre données

La puissance d’une base relationnelle réside dans les liens entre les tables. Voici comment les implémenter proprement :

Relation One-to-Many (1 → N)

C’est la relation la plus commune (ex: Un utlisateur possède plusieurs articles).

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    articles = db.relationship('Article', backref='author', lazy=True)

class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
Python

db.relationship() est utilisé côté « parent » (ici `User`).
db.ForeignKey()` est utilisé côté « enfant » (ici `Article`).

Relation One-to-One (1 → 1)

Exemple : Un utilisateur a un seul profil.

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    profile = db.relationship('Profile', backref='user', uselist=False)

class Profile(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    bio = db.Column(db.String(200))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
Python

uselist=False rend la relation unitaire (1:1).
Même principe que 1\:N sinon.

Relation Many-to-Many (N ↔ N)

Exemple : Un étudiant peut suivre plusieurs **cours**, et un cours peut avoir plusieurs étudiants.
Pour les cas complexes (ex: Étudiants et Cours), une table d’association est requise.

association_table = db.Table('association',
    db.Column('student_id', db.Integer, db.ForeignKey('student.id')),
    db.Column('course_id', db.Integer, db.ForeignKey('course.id'))
)

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    courses = db.relationship('Course', secondary=association_table, backref='students')

class Course(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
Python

Une table d’association (`association_table`) est nécessaire.
Utilisation de `secondary=` dans `db.relationship()` pour établir le lien.

Récapitulatif rapide :

Relation Côté A Côté B
One-to-Many db.relationship() db.ForeignKey()
One-to-One db.relationship(uselist=False) db.ForeignKey()
Many-to-Many db.relationship(secondary=…) Table d’association avec db.Table()

Grâce à **Flask-SQLAlchemy**, on manipule la base de données en Python, et avec Flask-Migrate, on gère les modifications de manière souple et sécurisée. 🚀

Laisser un commentaire

Your email address will not be published. Required fields are marked *.

*
*