Archives Wild Code School
Python

Framework Python Flask

Quête 33 sur 66 · 1 image archivée

Flask est un framework web minimaliste écrit en Python.

Il est conçu pour être léger et flexible, permettant aux développeurs de créer des applications web et des API rapidement et efficacement.


⚙️ Pré-requis

Avant de te lancer dans cette quête, il est préférable de savoir déjà :

  • Utiliser un terminal et exécuter des commandes basiques en ligne de commande.
  • Installer des paquets sur une distribution Linux basée sur Debian ou Ubuntu.
  • Avoir une VM ou un conteneur Debian/Ubuntu sans interface graphique, mais avec Python 3 installé.
  • Comprendre les bases de la programmation Python (structures de contrôle, fonctions, modules et POO).
  • Disposer d'un éditeur de texte comme nano, vim, ou un IDE comme VSCode.
Quêtes liées
Quêtes liées
Quêtes liées
Quêtes liées

🎯 Objectifs :

✅ Comprendre les bases de Flask ✅ Créer une application web fonctionnelle ✅ Manipuler des routes, templates et requêtes HTTP ✅ Intégrer une base de données pour stocker et récupérer des données dynamiques ✅ Construire une petite application interactive de gestion de tâches

Un framework est un ensemble d'outils, de bibliothèques et de bonnes pratiques conçu pour faciliter le développement d'applications.

Il fournit une structure de base et des fonctionnalités prêtes à l'emploi, permettant aux développeurs de se concentrer sur la logique spécifique de leur projet plutôt que de tout coder depuis zéro.

Caractéristiques principales d'un framework :

  • Productivité accrue : Il offre des solutions standardisées pour les tâches courantes, comme la gestion des requêtes web, la communication avec une base de données ou l'organisation du code
  • Modularité : Les frameworks sont souvent extensibles, permettant d'ajouter ou de remplacer des composants selon les besoins
  • Cohérence : Ils encouragent l'utilisation de bonnes pratiques et d'architectures claires, rendant le code plus maintenable et compréhensible

Exemples de frameworks dans différents domaines :

  • Développement web : Flask, Django, Ruby on Rails
  • Applications de bureau : Qt, Electron
  • Machine learning : TensorFlow, PyTorch
  • En résumé, un framework agit comme une boîte à outils qui simplifie le développement et aide à structurer les projets efficacement
↗
https://fr.wikipedia.org/wiki/Framework

Wikipedia - Framework

fr.wikipedia.org

Flask est un framework Python minimaliste conçu pour créer des applications web rapidement et efficacement.

Il repose sur deux composants essentiels : Werkzeug, une bibliothèque pour gérer les requêtes HTTP, et Jinja2, un moteur de templates permettant de générer des pages HTML dynamiques.

Flask se distingue par sa flexibilité : il n'impose aucune structure rigide ni dépendances spécifiques.

Cela en fait un choix privilégié pour les développeurs qui souhaitent garder un contrôle total sur leur projet.

En tant que micro-framework, Flask est à la fois léger et extensible, ce qui lui permet de s'adapter aussi bien à des applications simples qu'à des projets plus complexes.

📌 Quelques cas d'utilisation typiques :

  • Créer une interface web pour un script DevOps
  • Développer une API REST pour communiquer avec des systèmes
  • Construire un tableau de bord de monitoring
↗
https://flask.palletsprojects.com/en/stable/

Welcome to Flask

flask.palletsprojects.com

📖 Pourquoi apprendre Flask ?

✅ Facile à prendre en main : Avec Flask, tu peux obtenir un résultat fonctionnel en quelques lignes de code ✅ Flexible : Tu choisis les extensions et bibliothèques à utiliser (comme une base de données) ✅ Idéal pour débuter : La simplicité du framework te permet de te concentrer sur les concepts essentiels

🏗️ Structure d'une application Flask

Une application Flask repose sur un objet central : la classe Flask.

Cet objet représente le cœur de ton application.

C'est lui qui gère les interactions entre le navigateur (ou tout autre client) et ton code Python.

Comment ça fonctionne ?

  1. Création de l'application
    Pour démarrer, tu dois importer la classe Flask et créer un objet qui servira de point d'entrée à ton application :

    python
    from flask import Flask
    app = Flask(__name__)
    

    Ici, app est l'instance de la classe Flask. Elle joue le rôle de gestionnaire principal pour les requêtes entrantes, les réponses, et d'autres fonctionnalités.

  2. Les routes : connecter des URLs à des fonctions
    Une fois ton application créée, tu peux définir des routes. Une route est une association entre une URL et une fonction Python qui sera exécutée lorsque cette URL est appelée. Exemple :

    python
    @app.route('/')
    def home():
        return "Bienvenue sur Flask !"
    
    • @app.route('/') indique que cette fonction répondra à l'URL racine /.
    • La fonction home() retourne du contenu (ici une chaîne de caractères) qui sera affiché dans le navigateur.
  3. Démarrage du serveur
    Pour exécuter l'application, Flask lance un serveur de développement intégré. Ce serveur écoute les requêtes HTTP et renvoie les réponses générées par tes fonctions :

    python
    if __name__ == '__main__':
        app.run(debug=True)
    
    • app.run(debug=True) démarre le serveur en mode debug, ce qui :
      • Relance automatiquement l'application si tu modifies le code.
      • Affiche des messages d'erreur détaillés si quelque chose tourne mal.

Diagramme simplifié du flux d'une application Flask :

  1. Un client (navigateur, API, etc.) envoie une requête HTTP à une URL de ton application.
  2. Flask recherche la route correspondant à cette URL.
  3. La fonction associée à cette route est exécutée.
  4. La réponse générée par cette fonction est renvoyée au client.

Exemple complet :

python
from flask import Flask

# Création de l'application Flask
app = Flask(__name__)

# Définition d'une route pour l'URL "/"
@app.route('/')
def home():
    return "Bienvenue sur ma première application Flask !"

# Démarrage de l'application
if __name__ == '__main__':
    app.run(debug=True)
  • Accès à l'application : Lance le fichier avec python app.py puis ouvre un navigateur et visite http://127.0.0.1:5000.
  • Résultat attendu : La phrase "Bienvenue sur ma première application Flask !" sera affichée.

Pourquoi une structure simple ?

Flask est conçu pour être minimaliste.

Cette structure initiale permet de démarrer rapidement, mais tu peux la complexifier en organisant ton code dans des modules, en ajoutant des fichiers de configuration ou en intégrant des bases de données.

Werkzeug est un composant fondamental de Flask.

C'est une bibliothèque Python puissante qui fournit les outils nécessaires pour gérer les requêtes et réponses HTTP.

Bien qu'il fonctionne en arrière-plan, Werkzeug est au coeur de la manière dont Flask traite les interactions entre le client (navigateur ou API) et le serveur.

Pourquoi Werkzeug est-il important ?

  1. Gestion des requêtes : Werkzeug analyse les requêtes HTTP entrantes et extrait les informations essentielles, comme les paramètres, les en-têtes et le corps des requêtes
  2. Construction des réponses : Il facilite la création de réponses HTTP structurées avec un contrôle total sur le contenu, les en-têtes et les codes de statut
  3. Sécurité : Werkzeug offre des fonctionnalités intégrées pour sécuriser les applications web, comme la gestion des cookies et la protection contre certaines vulnérabilités
  4. Outils de développement : Il propose des outils pour simplifier le débogage, comme un serveur de développement et un analyseur de requêtes

Fonctionnalités notables de Werkzeug

  • WsgiRequest et WsgiResponse : Werkzeug suit le standard WSGI, ce qui le rend compatible avec une grande variété de serveurs web
  • Routing avancé : Werkzeug offre une gestion des routes performante, permettant de définir des URL dynamiques et des correspondances complexes
  • Middleware : Il supporte les middlewares, qui sont des couches intermédiaires permettant de transformer les requêtes ou réponses avant qu'elles n'atteignent l'application
↗
https://werkzeug.palletsprojects.com/en/stable/

Werkzeug - project page

werkzeug.palletsprojects.com

Les routes sont des chemins d'URL que tu définis pour que ton application Flask réponde aux requêtes des utilisateurs.

Chaque route est associée à une fonction Python qui définit la réponse à renvoyer (du texte, une page HTML, ou d'autres formats comme JSON).

Comment définir une route ?

Pour définir une route, on utilise le décorateur @app.route, suivi du chemin de l'URL souhaitée.

Exemple simple :

python
@app.route('/')
def home():
    return "Bienvenue sur la page d'accueil !"
  • @app.route('/') : Associe la fonction home() à l'URL / (la racine du site).
  • return : Indique ce que Flask doit renvoyer au client (ici du texte).

Routes dynamiques avec paramètres

Flask permet de définir des routes dynamiques, c'est-à-dire des routes avec des paramètres d'URL.

Ces paramètres peuvent changer en fonction de la requête de l'utilisateur.

Exemple :

python
@app.route('/hello/<name>')
def hello(name):
    return f"Salut, {name} !"
  • <name> : Définit une partie de l'URL comme un paramètre dynamique. Par exemple, /hello/Wilder passera "Wilder" comme valeur à la variable name.
  • return : La réponse inclut la valeur dynamique. Ici, Flask renverra : "Salut, Wilder !".

Spécifier les types de paramètres

Par défaut, Flask traite les paramètres comme des chaînes de caractères.

Tu peux spécifier le type attendu pour un paramètre :

python
@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f"Profil utilisateur avec l'ID {user_id}."
  • Types courants :
    • <int:var> : Accepte uniquement des entiers
    • <float:var> : Accepte des nombres à virgule
    • <string:var> : (par défaut) Accepte des chaînes de caractères
    • <path:var> : Accepte une chaîne qui peut contenir des barres obliques (/)

Exemple :

  • URL /user/123 => Affichera "Profil utilisateur avec l'ID 123."
  • URL /user/abc => Renverra une erreur, car abc n'est pas un entier

Associer plusieurs routes à une fonction

Une même fonction peut être associée à plusieurs routes différentes.

Cela peut être utile pour gérer des alias ou des redirections simples.

Exemple :

python
@app.route('/')
@app.route('/home')
def home():
    return "Bienvenue sur la page d'accueil !"

Ici, la fonction home() répondra aux URLs / et /home.

Méthodes HTTP : GET et POST

Par défaut, une route Flask répond aux requêtes GET (lecture).

Pour accepter d'autres types de requêtes, comme POST (envoi de données), tu dois les spécifier dans le décorateur @app.route.

Exemple :

python
@app.route('/submit', methods=['GET', 'POST'])
def submit():
    if request.method == 'POST':
        return "Données envoyées !"
    return "Utilisez POST pour soumettre des données."
  • methods=['GET', 'POST'] : Spécifie que la route accepte les requêtes GET et POST
  • request.method : Permet de vérifier le type de requête (GET ou POST)

Exemple complet avec plusieurs routes

python
from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def home():
    return "Bienvenue sur la page d'accueil !"


@app.route('/hello/<name>')
def hello(name):
    return f"Salut, {name} !"

@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f"Profil utilisateur avec l'ID {user_id}."

@app.route('/submit', methods=['POST'])
def submit():
    data = request.form['data']
    return f"Données reçues : {data}"

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

Résumé : Les bonnes pratiques avec les routes

  1. Nom explicite pour les fonctions : Utilise des noms qui décrivent leur rôle, comme user_profile ou submit.
  2. Documentation : Commente tes routes pour expliquer leur rôle et les paramètres attendus.
  3. Validation des paramètres : Si tu attends un type spécifique (comme un entier), utilise les spécifications de type <int> pour éviter des erreurs.
↗
https://flask.palletsprojects.com/en/stable/quickstart/#routing

Flask - routing

flask.palletsprojects.com

Pour créer des pages web dynamiques, Flask utilise un moteur de templates appelé Jinja2.

Les templates permettent de séparer la logique métier (code Python) de la présentation (HTML).

Cela améliore la clarté, la réutilisabilité et la maintenance de ton code.

Fonctionnement des templates

  1. Les fichiers de templates sont des fichiers HTML contenant des balises spéciales propres à Jinja2. Ces balises permettent d'injecter des données, de faire des boucles ou des conditions
  2. Flask utilise la fonction render_template() pour charger et afficher ces fichiers

Exemple de base : Template avec une variable

Fichier HTML templates/hello.html :

html
<!DOCTYPE html>
<html>
<head>
    <title>Page de salutations</title>
</head>
<body>
    <h1>Bonjour, {{ name }} !</h1>
</body>
</html>

Route Flask associée :

python
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/hello/<name>')
def hello(name):
    return render_template('hello.html', name=name)
  • {{ name }} : Jinja2 utilise des doubles accolades pour injecter des variables Python dans le fichier HTML.
  • render_template('hello.html', name=name) : Charge le fichier hello.html et passe la variable name au template.

Si tu accèdes à /hello/Wilder, la page affichera : "Bonjour, Wilder !".

Boucles et conditions dans Jinja2

Jinja2 te permet d'utiliser des structures comme des boucles et des conditions directement dans tes templates.

Exemple : Afficher une liste avec une boucle

Fichier templates/list.html :

html
<!DOCTYPE html>
<html>
<head>
    <title>Liste des noms</title>
</head>
<body>
    <h1>Liste des utilisateurs</h1>
    <ul>
        {% for user in users %}
            <li>{{ user }}</li>
        {% endfor %}
    </ul>
</body>
</html>

Route Flask associée :

python
@app.route('/users')
def users():
    user_list = ['Alice', 'Bob', 'Charlie']
    return render_template('list.html', users=user_list)
  • {% for user in users %} : Début d'une boucle.
  • {{ user }} : Affiche chaque élément de la liste users.

Résultat attendu :

html
<ul>
    <li>Alice</li>
    <li>Bob</li>
    <li>Charlie</li>
</ul>
Exemple : Utiliser des conditions

Fichier templates/conditional.html :

html
<!DOCTYPE html>
<html>
<head>
    <title>Condition</title>
</head>
<body>
    {% if logged_in %}
        <p>Bienvenue, utilisateur connecté !</p>
    {% else %}
        <p>Veuillez vous connecter.</p>
    {% endif %}
</body>
</html>

Route Flask associée :

python
@app.route('/status/<int:status>')
def status(status):
    return render_template('conditional.html', logged_in=bool(status))

Si status vaut 1, la page affichera "Bienvenue, utilisateur connecté !". Sinon, elle affichera "Veuillez vous connecter.".

Héritage de templates

Jinja2 permet d'hériter de templates pour éviter la duplication de code. Cela est utile pour partager une structure commune (comme un en-tête ou un pied de page) entre plusieurs pages.

Exemple : Template parent

Fichier templates/base.html :

html
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Mon application{% endblock %}</title>
</head>
<body>
    <header>
        <h1>Bienvenue sur mon site</h1>
    </header>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>
        <p>© 2024 Mon Application</p>
    </footer>
</body>
</html>
Exemple : Template enfant

Fichier templates/page.html :

html
{% extends "base.html" %}

{% block title %}Page d'exemple{% endblock %}

{% block content %}
    <p>Ceci est une page avec du contenu spécifique.</p>
{% endblock %}

Route Flask associée :

python
@app.route('/example')
def example():
    return render_template('page.html')

Le fichier page.html utilise la structure définie dans base.html et remplace les blocs définis par son propre contenu.

Résumé des balises Jinja2

  • {{ var }} : Injecter une variable.
  • {% ... %} : Ajouter une instruction (comme une boucle ou une condition).
  • {% block ... %}{% endblock %} : Définir des blocs pour l'héritage.

Exemple complet avec formulaire et affichage

Fichier templates/form.html :

html
<!DOCTYPE html>
<html>
<head>
    <title>Formulaire</title>
</head>
<body>
    <form action="/greet" method="POST">
        <label for="name">Ton nom :</label>
        <input type="text" id="name" name="name" required>
        <button type="submit">Envoyer</button>
    </form>
</body>
</html>

Route Flask associée :

python
from flask import request

@app.route('/form')
def form():
    return render_template('form.html')

@app.route('/greet', methods=['POST'])
def greet():
    name = request.form['name']
    return render_template('hello.html', name=name)

En visitant /form, tu peux soumettre un nom via le formulaire. Flask affichera ensuite une page personnalisée avec le message "Bonjour, [nom] !".

↗
https://jinja.palletsprojects.com/en/stable/

jinja2 - documentation

jinja.palletsprojects.com

Dans Flask, les requêtes HTTP sont au coeur des interactions entre le client (navigateur, API, etc.) et ton application.

Flask simplifie la gestion des différents types de requêtes, comme GET, POST, PUT, ou DELETE, en les associant à des routes.

Les différents types de requêtes HTTP

  1. GET : Récupère des informations (lecture).
    • Exemple : Charger une page web ou récupérer des données.
  2. POST : Envoie des données au serveur (écriture ou modification).
    • Exemple : Soumettre un formulaire ou ajouter une ressource.
  3. PUT : Met à jour une ressource existante.
  4. DELETE : Supprime une ressource.

Gérer les requêtes HTTP dans Flask

Par défaut, une route Flask accepte uniquement les requêtes GET. Pour gérer d'autres types de requêtes, tu dois les spécifier explicitement dans le décorateur @app.route.

Exemple avec une route acceptant GET et POST :

python
@app.route('/submit', methods=['GET', 'POST'])
def submit():
    if request.method == 'POST':
        return "Données envoyées via POST !"
    return "Bienvenue sur la page, utilisez POST pour soumettre des données."

Exemple avec un formulaire

Tu peux créer une route qui traite un formulaire soumis via POST.

Voici un exemple complet :

Formulaire HTML :
html
<form action="/submit" method="POST">
    <label for="username">Nom :</label>
    <input type="text" id="username" name="username" required>
    <button type="submit">Envoyer</button>
</form>
Route Flask associée :
python
from flask import Flask, request

app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def submit():
    username = request.form['username']
    return f"Bonjour, {username} !"

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

Récupérer des paramètres GET

Avec une requête GET, les paramètres sont envoyés dans l'URL après le caractère ?. Flask les récupère avec request.args.

Exemple :

python
@app.route('/search')
def search():
    query = request.args.get('q', default="rien", type=str)
    return f"Vous avez cherché : {query}"
  • URL : /search?q=Python
    Résultat : "Vous avez cherché : Python".
  • default="rien" : Valeur par défaut si le paramètre n'est pas fourni.

Récupérer des données POST

Les données envoyées via un formulaire POST sont accessibles avec request.form. Voici un exemple avancé avec plusieurs champs :

Formulaire HTML :
html
<form action="/submit-details" method="POST">
    <label for="name">Nom :</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email :</label>
    <input type="email" id="email" name="email" required>

    <button type="submit">Envoyer</button>
</form>
Route Flask associée :
python
@app.route('/submit-details', methods=['POST'])
def submit_details():
    name = request.form['name']
    email = request.form['email']
    return f"Nom : {name}, Email : {email}"

Exemple complet : Gérer des requêtes GET et POST

Voici un exemple où une route traite à la fois les requêtes GET et POST.

python
@app.route('/contact', methods=['GET', 'POST'])
def contact():
    if request.method == 'POST':
        name = request.form['name']
        message = request.form['message']
        return f"Message reçu de {name} : {message}"
    return '''
    <form action="/contact" method="POST">
        <label for="name">Nom :</label>
        <input type="text" id="name" name="name" required>
        <label for="message">Message :</label>
        <textarea id="message" name="message" required></textarea>
        <button type="submit">Envoyer</button>
    </form>
    '''
  • Si la requête est GET, Flask renvoie le formulaire HTML.
  • Si la requête est POST, Flask traite les données et renvoie un message de confirmation.

Résumé : Les objets Flask pour les requêtes

  • request.args : Récupère les paramètres GET dans l'URL.
  • request.form : Récupère les données POST envoyées par un formulaire.
  • request.method : Indique le type de requête (GET, POST, etc.).

Avec ces outils, tu peux facilement gérer toutes sortes de requêtes HTTP dans ton application Flask !

Flask ne force pas l'utilisation d'une base de données spécifique.

Pour répondre à ce besoin, l'extension Flask-SQLAlchemy est fréquemment utilisée pour interagir avec des bases comme SQLite, PostgreSQL, ou MySQL.

Elle simplifie les opérations courantes, comme la création, la lecture, la mise à jour et la suppression de données.

Installation

Pour utiliser SQLAlchemy dans Flask, installe l'extension avec :

bash
pip install flask-sqlalchemy

Configuration de la base de données

Voici comment configurer une base de données SQLite dans une application Flask :

  1. Importer et configurer SQLAlchemy :

    python
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    db = SQLAlchemy(app)
    
    • SQLALCHEMY_DATABASE_URI : Spécifie l'URL de connexion à la base de données (ici SQLite).
    • SQLALCHEMY_TRACK_MODIFICATIONS : Désactive le suivi des modifications pour optimiser les performances.
  2. Définir un modèle : Un modèle est une classe Python qui représente une table dans la base de données.

    Exemple pour une table de tâches :

    python
    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)
    
        def __repr__(self):
            return f'<Task {self.title}>'
    
    • db.Column : Définit les colonnes de la table.
    • Types courants :
      • db.Integer : Pour les nombres entiers.
      • db.String(100) : Pour les chaînes de caractères (limitées ici à 100 caractères).
      • db.Boolean : Pour les valeurs booléennes.
  3. Créer la base de données : Flask-SQLAlchemy fournit des commandes pour initialiser la base. Dans une session Python :

    bash
    python
    >>> from app import db
    >>> db.create_all()
    

    Cela crée une base SQLite app.db et les tables définies dans tes modèles.

Opérations CRUD (Créer, Lire, Mettre à jour, Supprimer)

Ajouter des données :

Ajoute une nouvelle tâche :

python
@app.route('/add/<title>')
def add_task(title):
    task = Task(title=title)
    db.session.add(task)
    db.session.commit()
    return f"Tâche ajoutée : {title}"
Lire des données :

Récupère toutes les tâches :

python
@app.route('/tasks')
def get_tasks():
    tasks = Task.query.all()
    return {task.id: task.title for task in tasks}
Mettre à jour des données :

Met à jour le statut d'une tâche :

python
@app.route('/complete/<int:task_id>')
def complete_task(task_id):
    task = Task.query.get(task_id)
    if task:
        task.completed = True
        db.session.commit()
        return f"Tâche {task_id} complétée !"
    return "Tâche introuvable."
Supprimer des données :

Supprime une tâche :

python
@app.route('/delete/<int:task_id>')
def delete_task(task_id):
    task = Task.query.get(task_id)
    if task:
        db.session.delete(task)
        db.session.commit()
        return f"Tâche {task_id} supprimée."
    return "Tâche introuvable."

Exemple complet

Voici une application Flask qui gère une liste de tâches avec une base de données SQLite.

python
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

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)

# Initialisation de la base de données
@app.before_first_request
def create_tables():
    db.create_all()

# Ajouter une tâche
@app.route('/add', methods=['POST'])
def add_task():
    data = request.json
    new_task = Task(title=data['title'])
    db.session.add(new_task)
    db.session.commit()
    return jsonify({"message": "Tâche ajoutée"}), 201

# Obtenir toutes les tâches
@app.route('/tasks', methods=['GET'])
def get_tasks():
    tasks = Task.query.all()
    return jsonify([{ "id": task.id, "title": task.title, "completed": task.completed } for task in tasks])

# Compléter une tâche
@app.route('/complete/<int:task_id>', methods=['PUT'])
def complete_task(task_id):
    task = Task.query.get(task_id)
    if task:
        task.completed = True
        db.session.commit()
        return jsonify({"message": f"Tâche {task_id} complétée"})
    return jsonify({"error": "Tâche introuvable"}), 404

# Supprimer une tâche
@app.route('/delete/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = Task.query.get(task_id)
    if task:
        db.session.delete(task)
        db.session.commit()
        return jsonify({"message": f"Tâche {task_id} supprimée"})
    return jsonify({"error": "Tâche introuvable"}), 404

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

Avec cet exemple, tu disposes d'une API complète pour gérer des tâches via une base de données.

🛠️ Un peu de pratique

  1. 1

    Étape 1 : Mise en place

    Installe Flask et Flask-SQLAlchemy :

    bash
    pip install flask flask-sqlalchemy
    
  2. 2

    Crée un fichier `app.py` avec le code suivant

    python
       from flask import Flask, render_template, request
       from flask_sqlalchemy import SQLAlchemy
    
       app = Flask(__name__)
       app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
       db = SQLAlchemy(app)
    
       class Task(db.Model):
           id = db.Column(db.Integer, primary_key=True)
           title = db.Column(db.String(100), nullable=False)
    
       @app.route('/')
       def home():
           tasks = Task.query.all()
           return render_template('index.html', tasks=tasks)
    
       @app.route('/add', methods=['POST'])
       def add_task():
           title = request.form['title']
           new_task = Task(title=title)
           db.session.add(new_task)
           db.session.commit()
           return "Tâche ajoutée !"
    
       if __name__ == '__main__':
           app.run(debug=True)
    
  3. 3

    Crée un fichier `templates/index.html`

    html
       <!DOCTYPE html>
       <html>
       <head>
           <title>Gestion des tâches</title>
       </head>
       <body>
           <h1>Liste des tâches</h1>
           <ul>
               {% for task in tasks %}
                   <li>{{ task.title }}</li>
               {% endfor %}
           </ul>
           <form action="/add" method="POST">
               <input type="text" name="title" placeholder="Nouvelle tâche">
               <button type="submit">Ajouter</button>
           </form>
       </body>
       </html>
    
  4. 4

    Initialise la base de données

    bash
       python
       >>> from app import app, db
       >>> with app.app_context():
       ...     db.create_all()
       ...     print("Toutes les tables ont été créées avec succès !")
       ...
    
  5. 5

    Lance l'application et teste-la sur [http://127.0.0.1:5000](http://127.0.0.1:5000)

quiz
true||true|||true
# Quelle méthode Python est utilisée pour associer une URL à une fonction dans Flask ?
[] define_route
[x] @app.route
[] flask.bind
[] route_url

# Quel moteur de templates est utilisé par Flask pour générer des pages HTML dynamiques ?
[] DjangoTemplates
[] Bootstrap
[x] Jinja2
[] SQLAlchemy

# Quelle méthode permet d'extraire des données envoyées via un formulaire POST dans Flask ?
[] request.data
[] form.get_data()
[x] request.form
[] post.get()

# Quel type de base de données est configuré par défaut dans la plupart des tutoriels Flask ?
[] PostgreSQL
[] MySQL
[x] SQLite
[] OracleDB

# Quelle extension est utilisée pour intégrer facilement des bases de données relationnelles dans Flask ?
[] flask-db
[] flask-orm
[x] Flask-SQLAlchemy
[] Flask-Data

💪 Challenge

Crée une application Flask complète qui gère une liste de tâches avec une base de données SQLite.

Ton application devra permettre d'ajouter, de visualiser, de marquer comme terminées, et de supprimer des tâches.

L'objectif est de mettre en pratique les concepts étudiés tout en développant une application fonctionnelle.


🧩 Objectifs

  1. Construire une application Flask fonctionnelle avec une structure organisée.
  2. Configurer une base de données SQLite pour stocker les tâches.
  3. Créer des routes pour gérer les fonctionnalités CRUD (Create, Read, Update, Delete).
  4. Utiliser des templates Jinja2 pour l'interface utilisateur.
  5. Publier le projet sur un dépôt GitLab.

⚙️ Fonctionnalités attendues

Ton application devra inclure les fonctionnalités suivantes :

  1. Afficher la liste des tâches :

    • Les tâches sont affichées sur la page principale avec leur statut (terminée ou non).
  2. Ajouter une nouvelle tâche :

    • Un formulaire permet d'ajouter une tâche à la base de données.
  3. Marquer une tâche comme terminée :

    • Un bouton ou un lien permet de changer le statut d'une tâche pour indiquer qu'elle est terminée.
  4. Supprimer une tâche :

    • Un bouton ou un lien permet de supprimer une tâche de la base de données.
  5. Utiliser un design basique :

    • Utilise des templates HTML avec Jinja2 pour afficher les tâches.

📋 Spécifications techniques

  • Base de données : SQLite
    • Une table tasks avec les colonnes :
      • id (clé primaire, entier).
      • title (texte, obligatoire).
      • completed (booléen, par défaut False).
  • Routes à implémenter :
    • GET / : Affiche la liste des tâches.
    • POST /add : Ajoute une nouvelle tâche.
    • POST /complete/<id> : Marque une tâche comme terminée.
    • POST /delete/<id> : Supprime une tâche.
  • Dossiers et fichiers suggérés :
    • app.py : Fichier principal.
    • templates/ : Contiendra les fichiers HTML (par exemple, index.html).

🛠️ Indices

  • Pour créer la base de données SQLite, utilise Flask-SQLAlchemy :
    python
    from flask_sqlalchemy import SQLAlchemy
    db = SQLAlchemy(app)
    
  • Pour exécuter des commandes SQL et gérer les objets dans la base, utilise des modèles :
    python
    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)
    
  • Utilise des formulaires HTML simples avec l'attribut method="POST" pour soumettre des données.
  • Utilise request.form pour récupérer les données soumises via un formulaire.

🔎 Critères d'acceptation

  1. Fonctionnalité complète :
    • Toutes les fonctionnalités (ajout, visualisation, marquage comme terminé, suppression) sont implémentées.
  2. Base de données fonctionnelle :
    • Les tâches sont bien enregistrées dans une base SQLite.
  3. Interface utilisateur simple et claire :
    • Les tâches sont affichées dans un tableau ou une liste.
    • Les formulaires sont accessibles et fonctionnels.
  4. Code organisé :
    • Structure propre et lisible (par exemple, séparer le code HTML dans des templates).
  5. Versionné et documenté
    • Publier le projet sur un dépôt GitLab avec un historique de commits clair et bien documenté.
    • L'historique des commits doit refléter une progression logique du projet.
    • Ajoute un fichier README.md expliquant les étapes pour exécuter le projet et ses principales fonctionnalités.

🚀 Défi supplémentaire

Ajoute une nouvelle fonctionnalité pour trier les tâches par :

  • Leur statut (terminée ou non terminée).
  • Leur ordre de création (plus récentes ou plus anciennes).