Tutoriel Flask et Lovable : Créez Votre Première API Facilement

Absolument ! Voici une version complète de l’article tutoriel sur la création d’une To-Do List avec Flask et SQLAlchemy, en reprenant la structure amorcée et en la développant.


Tutoriel Complet : Créez Votre To-Do List avec Flask et SQLAlchemy

Salut les codeurs et codeuses ! Bienvenue sur Aircoding.fr, votre QG pour tout ce qui touche au développement web, qu’il soit assisté par l’IA ou construit pas à pas comme aujourd’hui. On va mettre les mains dans le code pour bâtir une application web classique mais essentielle : une To-Do List interactive en utilisant Flask, un micro-framework Python populaire, et SQLAlchemy, un ORM puissant pour gérer notre base de données.

Vous découvrez Flask, SQLAlchemy, ou même le développement web ? Pas de panique ! Ce tutoriel est conçu pour vous guider étape par étape, de la configuration initiale au déploiement d’une application fonctionnelle. L’objectif est simple : démystifier la création d’applications web et vous montrer que vous pouvez construire des outils utiles rapidement.

Prérequis

Avant de plonger dans le vif du sujet, assurez-vous d’avoir :

  • Python installé sur votre machine (version 3.7 ou supérieure recommandée). Vous pouvez le télécharger sur python.org.
  • pip, le gestionnaire de paquets Python (généralement inclus avec Python).
  • Un terminal ou une invite de commandes.
  • Des connaissances de base en Python et une compréhension élémentaire du HTML.

Ouvrez votre terminal et installons les bibliothèques nécessaires :

Bash

pip install Flask Flask-SQLAlchemy

Étape 1 : Initialisation du Projet et Modèle de Données

Commençons par organiser notre projet et définir comment nos tâches seront stockées.

  1. Créez un dossier pour votre projet, par exemple flask_todo_app.
  2. À l’intérieur de ce dossier, créez un fichier nommé app.py. C’est ici que résidera notre code Flask principal.
  3. Créez également un sous-dossier nommé templates. Flask cherchera nos fichiers HTML ici.

Ouvrez app.py et insérons le code de base pour initialiser Flask et SQLAlchemy, ainsi que notre modèle de données pour les tâches :

Extrait de code

# app.py
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import os

# Configuration de l'application Flask
app = Flask(__name__)

# Configuration de la base de données SQLAlchemy
# Utilisation de SQLite pour la simplicité, stocké dans le dossier 'instance'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Désactive les notifications inutiles

# Initialisation de l'extension SQLAlchemy avec notre application Flask
db = SQLAlchemy(app)

# Définition du modèle de données pour une tâche (Todo)
class Todo(db.Model):
    id = db.Column(db.Integer, primary_key=True) # Identifiant unique pour chaque tâche
    content = db.Column(db.String(200), nullable=False) # Le texte de la tâche, ne peut pas être vide
    completed = db.Column(db.Boolean, default=False) # Statut de la tâche (complétée ou non)
    date_created = db.Column(db.DateTime, default=datetime.utcnow) # Date de création de la tâche

    # Fonction pour représenter l'objet Todo quand on l'affiche (utile pour le debug)
    def __repr__(self):
        return f'<Task {self.id}>'

# Cette fonction s'assure que les tables de la base de données sont créées
# avant la première requête si elles n'existent pas déjà.
@app.before_request
def create_tables():
    # Crée les tables UNIQUEMENT si elles n'existent pas déjà
    # Pour éviter de le faire à chaque requête en production,
    # on peut utiliser `flask db init`, `flask db migrate`, `flask db upgrade` avec Flask-Migrate
    # Mais pour ce tutoriel simple, ceci est suffisant.
    db.create_all()


# --- Les routes seront définies ici plus tard ---


# Point d'entrée pour exécuter l'application
if __name__ == '__main__':
    app.run(debug=True) # debug=True active le mode débuggage (rechargement auto, infos d'erreur)

Explication rapide :

  • On importe les modules nécessaires.
  • On crée une instance de l’application Flask.
  • On configure l’URI de notre base de données (sqlite:///todo.db créera un fichier todo.db dans le dossier instance de votre projet) et on initialise SQLAlchemy.
  • On définit la classe Todo qui hérite de db.Model. Chaque attribut de classe défini avec db.Column correspondra à une colonne dans notre table de base de données.
  • @app.before_request avec db.create_all() assure que la table todo est créée avant que l’application ne commence à traiter les requêtes.
  • if __name__ == '__main__': lance le serveur de développement Flask si le script est exécuté directement. debug=True est très utile pendant le développement.

Étape 2 : Création des Templates HTML

Une application web a besoin d’une interface ! Utilisons Jinja2 (le moteur de template de Flask) pour créer nos pages HTML.

Créez un fichier base.html dans le dossier templates. Il servira de squelette commun à nos pages :

HTML

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> {# Lien vers un futur CSS #}
    {% block head %}{% endblock %} {# Bloc pour ajouter des éléments spécifiques dans <head> #}
    <title>{% block title %}To-Do App{% endblock %}</title> {# Bloc pour le titre de la page #}
</head>
<body>
    <div class="container">
        {% block body %}{% endblock %} {# Bloc principal où le contenu de la page sera inséré #}
    </div>
</body>
</html>

Maintenant, créez index.html dans le dossier templates. C’est la page principale qui affichera notre liste et le formulaire d’ajout :

HTML

{% extends 'base.html' %} {# Hérite de notre template de base #}

{% block head %}
    {# On pourrait ajouter des styles spécifiques ici si besoin #}
{% endblock %}

{% block title %}Ma To-Do List{% endblock %}

{% block body %}
<h1 style="text-align: center;">Ma Super To-Do List</h1>

<div class="form-container">
    {# Formulaire pour ajouter une nouvelle tâche #}
    <form method="POST" action="{{ url_for('index') }}"> {# L'action pointe vers notre route principale #}
        <input type="text" name="content" id="content" placeholder="Entrez une nouvelle tâche..." required>
        <button type="submit">Ajouter</button>
    </form>
</div>

<div class="task-list">
    {% if tasks|length < 1 %} {# Vérifie s'il y a des tâches #}
        <p style="text-align: center;">Aucune tâche pour le moment. Ajoutez-en une !</p>
    {% else %}
        <table>
            <thead>
                <tr>
                    <th>Tâche</th>
                    <th>Ajoutée le</th>
                    <th>Statut</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                {# Boucle pour afficher chaque tâche #}
                {% for task in tasks %}
                    <tr class {% if task.completed %} "completed" {% endif %}>
                        <td>{{ task.content }}</td>
                        <td>{{ task.date_created.strftime('%d/%m/%Y') }}</td> {# Formate la date #}
                        <td>{% if task.completed %}Complétée{% else %}En cours{% endif %}</td>
                        <td>
                            {# Liens pour les actions (Update/Delete) #}
                            <a href="{{ url_for('update', id=task.id) }}">
                                {% if task.completed %}Annuler{% else %}Compléter{% endif %}
                            </a>
                            <a href="{{ url_for('delete', id=task.id) }}" class="delete-btn">Supprimer</a>
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    {% endif %}
</div>
{% endblock %}

Explication rapide :

  • {% extends 'base.html' %} : Indique que ce template hérite de base.html.
  • {% block ... %} et {% endblock %} : Définissent des blocs qui peuvent être surchargés par les templates enfants ou qui insèrent du contenu.
  • {{ ... }} : Affiche la valeur d’une variable passée par Flask (ex: {{ task.content }}).
  • {% ... %} : Utilisé pour les logiques de template (boucles for, conditions if).
  • url_for('...') : Génère l’URL pour une fonction de route donnée (plus sûr que d’écrire les URLs en dur).
  • Le formulaire envoie les données via POST à la route index.
  • La boucle for itère sur la liste tasks (qu’on passera depuis Flask) pour afficher chaque tâche.
  • Des liens pointent vers des futures routes update et delete, en passant l’ID de la tâche.

Étape 3 : Routes pour Afficher et Ajouter des Tâches

Retournons dans app.py pour créer la logique qui gère l’affichage de la page d’accueil et l’ajout de nouvelles tâches. Modifiez/Ajoutez la route index comme suit :

Python

# app.py (suite)

# Route principale : affiche les tâches et gère l'ajout de nouvelles tâches
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        # Si le formulaire est soumis (méthode POST)
        task_content = request.form['content'] # Récupère le contenu du champ 'content' du formulaire
        if task_content: # Vérifie si le contenu n'est pas vide
            new_task = Todo(content=task_content) # Crée une nouvelle instance de tâche

            try:
                db.session.add(new_task) # Ajoute la nouvelle tâche à la session de la base de données
                db.session.commit() # Sauvegarde les changements dans la base de données
                return redirect(url_for('index')) # Redirige vers la page d'accueil (pour éviter de resoumettre le formulaire avec F5)
            except Exception as e:
                print(f"Erreur lors de l'ajout de la tâche: {e}")
                return "Une erreur est survenue lors de l'ajout de votre tâche."
        else:
            # Gérer le cas où le contenu est vide si 'required' n'était pas dans le HTML
            pass # Ou afficher un message d'erreur

    else:
        # Si on accède à la page normalement (méthode GET)
        tasks = Todo.query.order_by(Todo.date_created).all() # Récupère toutes les tâches, triées par date
        return render_template('index.html', tasks=tasks) # Rend le template HTML en passant la liste des tâches

# --- Le reste du code (model, if __name__...) reste identique ---

Explication :

  • @app.route('/', methods=['GET', 'POST']) : Définit que cette fonction gère les requêtes GET et POST pour l’URL racine (/).
  • if request.method == 'POST': : Vérifie si la requête est une soumission de formulaire.
    • request.form['content'] : Accède aux données envoyées par le formulaire.
    • new_task = Todo(...) : Crée un nouvel objet tâche.
    • db.session.add(new_task) : Ajoute l’objet à la session SQLAlchemy (prêt à être sauvegardé).
    • db.session.commit() : Écrit les changements (la nouvelle tâche) dans la base de données.
    • redirect(url_for('index')) : Redirige l’utilisateur vers la page d’accueil après l’ajout (pattern Post/Redirect/Get).
  • else: (pour les requêtes GET) :
    • tasks = Todo.query.order_by(Todo.date_created).all() : Interroge la base de données pour récupérer toutes les tâches (.all()) et les trie (.order_by()).
    • render_template('index.html', tasks=tasks) : Charge le fichier index.html et lui passe la variable tasks contenant notre liste de tâches. Le template pourra alors l’utiliser ({% for task in tasks %}).

À ce stade, vous devriez pouvoir lancer python app.py dans votre terminal, ouvrir votre navigateur à l’adresse http://127.0.0.1:5000 (ou similaire), voir le titre, le formulaire, et ajouter des tâches qui s’afficheront dans la liste !

Étape 4 : Suppression des Tâches

Ajoutons la possibilité de supprimer une tâche. Nous avons déjà le lien dans index.html. Créons la route correspondante dans app.py :

Python

# app.py (suite)

# Route pour supprimer une tâche
@app.route('/delete/<int:id>')
def delete(id):
    task_to_delete = Todo.query.get_or_404(id) # Récupère la tâche par son ID ou renvoie une erreur 404 si non trouvée

    try:
        db.session.delete(task_to_delete) # Supprime la tâche de la session
        db.session.commit() # Sauvegarde le changement (suppression)
        return redirect(url_for('index')) # Redirige vers l'accueil
    except Exception as e:
        print(f"Erreur lors de la suppression de la tâche: {e}")
        return "Une erreur est survenue lors de la suppression de votre tâche."

# --- Le reste du code reste identique ---

Explication :

  • @app.route('/delete/<int:id>') : Définit une route qui accepte un entier (id) dans l’URL.
  • Todo.query.get_or_404(id) : Méthode très pratique pour récupérer un objet par sa clé primaire. Si l’ID n’existe pas, elle renvoie automatiquement une page 404 Not Found.
  • db.session.delete(...) et db.session.commit() : Suppriment l’objet de la base de données.

Étape 5 : Mise à Jour des Tâches (Compléter / Annuler)

Implémentons la fonctionnalité pour marquer une tâche comme complétée ou la remettre en cours. Le lien est déjà dans index.html. Ajoutons la route dans app.py :

Python

# app.py (suite)

# Route pour mettre à jour le statut d'une tâche (complétée/non complétée)
@app.route('/update/<int:id>')
def update(id):
    task_to_update = Todo.query.get_or_404(id) # Récupère la tâche par ID ou 404

    # Inverse le statut 'completed'
    task_to_update.completed = not task_to_update.completed

    try:
        db.session.commit() # Sauvegarde le changement de statut
        return redirect(url_for('index')) # Redirige vers l'accueil
    except Exception as e:
        print(f"Erreur lors de la mise à jour de la tâche: {e}")
        return "Une erreur est survenue lors de la mise à jour de votre tâche."

# --- Le reste du code reste identique ---

Explication :

  • La logique est similaire à la suppression, mais au lieu de supprimer, on modifie l’attribut completed de l’objet task_to_update.
  • task_to_update.completed = not task_to_update.completed : C’est une façon simple d’inverser une valeur booléenne (True devient False, False devient True).
  • db.session.commit() sauvegarde ce changement dans la base de données.

Étape 6 (Optionnelle) : Un Peu de Style CSS

Notre application est fonctionnelle, mais un peu austère. Ajoutons quelques styles simples.

  1. Créez un dossier static à la racine de votre projet.
  2. À l’intérieur de static, créez un sous-dossier css.
  3. Dans static/css, créez un fichier style.css.
  4. Assurez-vous que base.html contient bien la ligne <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}"> dans le <head>.

Ajoutez quelques règles CSS dans static/css/style.css :

CSS

/* static/css/style.css */
body {
    font-family: sans-serif;
    margin: 0;
    background-color: #f4f4f4;
}

.container {
    max-width: 800px;
    margin: 30px auto;
    background: #fff;
    padding: 20px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
}

h1 {
    color: #333;
}

.form-container {
    margin-bottom: 20px;
    display: flex;
}

.form-container input[type="text"] {
    flex-grow: 1;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px 0 0 4px;
}

.form-container button {
    padding: 10px 15px;
    background-color: #5cb85c;
    color: white;
    border: none;
    border-radius: 0 4px 4px 0;
    cursor: pointer;
}

.form-container button:hover {
    background-color: #4cae4c;
}

.task-list table {
    width: 100%;
    border-collapse: collapse;
}

.task-list th, .task-list td {
    border: 1px solid #ddd;
    padding: 8px;
    text-align: left;
}

.task-list th {
    background-color: #f2f2f2;
}

.task-list tr.completed td:first-child {
    text-decoration: line-through;
    color: grey;
}

.task-list td a {
    margin-right: 5px;
    text-decoration: none;
    color: #0275d8;
}
.task-list td a:hover {
    text-decoration: underline;
}

.task-list td a.delete-btn {
    color: #d9534f;
}

Relancez votre application (ou laissez le mode debug faire son travail) et rechargez la page pour voir les changements !

Conclusion

Félicitations ! Vous avez construit une application web To-Do List complète et fonctionnelle avec Flask et SQLAlchemy. Vous avez vu comment :

  • Initialiser un projet Flask.
  • Définir un modèle de données avec SQLAlchemy.
  • Créer des templates HTML avec Jinja2.
  • Gérer les requêtes GET et POST dans les routes.
  • Effectuer les opérations CRUD (Create, Read, Update, Delete) sur votre base de données.
  • Utiliser les redirections et url_for.
  • Ajouter un style basique avec CSS.

Ce projet est une excellente base pour comprendre les fondamentaux du développement web avec Python. À partir d’ici, vous pouvez explorer des fonctionnalités plus avancées : authentification utilisateur, catégories de tâches, dates d’échéance, utilisation de bases de données plus robustes comme PostgreSQL, ou même voir comment des outils comme Lovable AI pourraient vous aider à générer certaines parties de ce code plus rapidement grâce au Vibe Coding !

L’important est de continuer à pratiquer et à construire. Le développement web est un voyage passionnant !

Laisser un commentaire

Retour en haut