Skip to content

1. Introduction

Le PDF du document est |ICI|.

Les codes du document sont |ICI|.

Ce document est un produit de l'IA Claude d'Anthropic. Il fait suite au document Introduction étape par étape au framework web [Spring MVC] (2026), qui faisait lui-même suite aux documents Introduction étape par étape au framework web [ASP.NET Core MVC] et Introduction étape par étape au framework web [NestJS] (2026). Le présent document transpose le cours [Spring MVC] dans le monde [Python] :

  • le framework [Spring MVC] et le langage [Java] sont remplacés par le framework [Flask] 3.1 et le langage [Python] (version 3.12 ou plus récente) ;
  • les vues [Thymeleaf] sont remplacées par des vues [Jinja2], le moteur de vues de [Flask] ;
  • la validation [Bean Validation] est remplacée par la bibliothèque [Pydantic] (les paramètres des actions) et par la bibliothèque [WTForms] (les formulaires HTML) ;
  • [Spring Security] est remplacé par quelques dizaines de lignes de [Python] écrites pour l'occasion, qui s'appuient sur les bibliothèques [PyJWT] (les jetons JWT) et [bcrypt] (le hachage des mots de passe) ;
  • l'ORM [Hibernate] et [Spring Data JPA] sont remplacés par l'ORM [SQLAlchemy], toujours avec une base [MySQL].

Le document suit exactement la progression du cours [Spring MVC] : d'abord de nombreux petits projets, chacun centré sur une notion, puis une étude de cas complète, une application web de prise de rendez-vous pour un cabinet de médecins, dont tous les fichiers sont commentés. Les exemples portent les mêmes numéros et traitent les mêmes sujets que dans les cours [Spring MVC] et [ASP.NET Core MVC] : un lecteur qui connaît l'un de ces cours peut comparer les frameworks exemple par exemple. Ce n'est pourtant pas nécessaire : ce document se lit seul, et ne suppose aucune connaissance de [Spring] ni d'[ASP.NET]. On suppose seulement connues les bases de la programmation web (le protocole HTTP, le langage HTML) et celles du langage [Python] (fonctions, classes, dictionnaires, modules). Un précédent cours du réviseur de celui-ci, Introduction au langage Python et au framework web Flask par l'exemple (2020), présente le langage [Python] lui-même, pour qui aurait besoin de le découvrir d'abord.

1.1. La place de Flask dans une application web

Une application web est souvent construite en couches, chaque couche ne parlant qu'à ses voisines :

Image

  • la couche web reçoit les requêtes HTTP du navigateur et lui renvoie des pages HTML. C'est elle que [Flask] nous aide à écrire ;
  • la couche métier contient les règles de gestion de l'application (« un patient ne peut avoir qu'un rendez-vous à venir », par exemple). Elle ignore tout du web : elle pourrait aussi bien servir une application en ligne de commande ;
  • la couche d'accès aux données (couche [DAO], pour [Data Access Object]) lit et écrit dans la base de données. Nous utiliserons [SQLAlchemy], un ORM ([Object Relational Mapper]) qui fait correspondre les lignes des tables et des objets [Python].

La couche web suit elle-même le modèle [MVC] ([Model – View – Controller]) :

  • le contrôleur (C) est un ensemble de fonctions [Python], appelées actions, qui traitent chacune un type de requête (par exemple [GET /agenda]). Une action lit les paramètres de la requête, fait travailler la couche métier, puis choisit la vue à afficher ;
  • le modèle (M) est l'ensemble des données que l'action transmet à la vue ;
  • la vue (V) est un fichier [Jinja2] (extension [.html]) : une page HTML qui contient des expressions [{{ ... }}] et des instructions [{% ... %}] ([{% if %}], [{% for %}]...), que le moteur [Jinja2] remplace par les données du modèle.

Une remarque de vocabulaire, pour éviter une confusion : la documentation de [Flask] appelle view function (« fonction de vue ») la fonction qui traite une requête, et template (« gabarit ») le fichier [Jinja2]. Ce document garde le vocabulaire du modèle [MVC], celui des cours [Spring MVC] et [ASP.NET Core MVC] : la fonction qui traite une requête est une action, le fichier [Jinja2] qui fabrique la page est une vue, et le mot gabarit désigne la vue commune dont les autres pages héritent (chapitre 4).

Le traitement d'une requête suit les étapes numérotées du schéma :

  • 1 : le navigateur envoie une requête HTTP, par exemple [GET /agenda?idMedecin=1&jour=2026-09-26] ;
  • 2 : le serveur web reçoit la requête et la confie à l'application [Flask]. Pendant le développement, ce serveur est celui de [Werkzeug], la bibliothèque sur laquelle [Flask] est bâti ; en production, ce sera un serveur comme [Waitress] ou [Gunicorn]. [Werkzeug] compare le chemin demandé aux routes de l'application et choisit l'action chargée de cette requête : c'est le routage. Avant l'action, la requête peut encore traverser des fonctions exécutées pour toutes les requêtes ([before_request]), que nous découvrirons au fil des chapitres ;
  • 3 : l'action demande à la couche métier les données dont elle a besoin ; la couche métier s'adresse, si nécessaire, à la couche [DAO], qui interroge la base [MySQL] en SQL ;
  • 4 : l'action construit le modèle M de la vue et demande au moteur [Jinja2] de fabriquer la page (fonction [render_template]) ;
  • 5 : la page HTML fabriquée par la vue est la réponse de l'action, que [Flask] renvoie au navigateur.

[Flask] est l'un des deux frameworks web les plus utilisés du monde [Python], avec [Django]. Gratuit et libre, il fonctionne partout où fonctionne [Python] ([Windows], [Linux], [macOS]). C'est un micro-framework : son cœur est volontairement petit (le routage, les requêtes et les réponses, les sessions, les vues [Jinja2]), et tout le reste (la validation des formulaires, l'accès aux bases de données, l'authentification...) est confié à des bibliothèques choisies par le développeur. Là où [Spring Boot] configure lui-même un ensemble cohérent de composants, [Flask] laisse le développeur assembler les siens : l'application est plus explicite, et l'on voit tout ce qui s'y passe. C'est d'ailleurs ce qui en fait un bon outil pour apprendre : presque rien n'est caché. [Flask] sait fabriquer aussi bien des serveurs qui renvoient du JSON à un client [JavaScript] ([Angular], [React], [Flutter]...) que des applications web classiques, où c'est le serveur qui fabrique les pages HTML, le navigateur se contentant de les afficher. C'est ce second usage qu'étudie ce document. Deux idées de [Python] reviennent à chaque page : les décorateurs ([@app.get("/")], [@app.before_request]...), qui associent une fonction à un rôle, et le passage explicite des objets dont chaque fonction a besoin, là où [Spring] les injecte automatiquement.

1.2. Les outils utilisés

Les exemples ont été écrits et testés avec les outils suivants (leur installation est décrite en annexe) :

  • [Python] 3.13 (toute version 3.12 ou plus récente convient). L'installeur de [Python] fournit aussi l'outil [pip], qui télécharge et installe les bibliothèques, et le module [venv], qui crée des environnements virtuels (nous verrons plus bas ce que c'est) ;
  • l'éditeur [Visual Studio Code], avec l'extension [Python] de Microsoft (elle installe aussi l'extension [Pylance], qui analyse le code) ;
  • un navigateur récent ([Chrome], [Firefox], [Edge]) ;
  • l'outil en ligne de commande [curl], qui affiche les réponses HTTP brutes (il est livré avec [Windows] 10 et 11) ;
  • le SGBD [MySQL] (ou [MariaDB]), par exemple celui de [Laragon] sous [Windows], à partir du chapitre sur l'accès aux données, et pour l'étude de cas.

Contrairement au [JDK], qui ne contient pas [Spring], [Python] est livré avec une bibliothèque standard très riche ; mais [Flask] et les autres bibliothèques du document n'en font pas partie : [pip] les télécharge depuis le dépôt [PyPI] ([Python Package Index]) lors de l'installation (il faut donc être connecté à Internet ce jour-là). Chaque projet décrit ses bibliothèques dans un fichier [requirements.txt]. Le tableau suivant les présente, avec les versions utilisées :

Bibliothèque
Rôle
Version
[Flask]
le framework web : routage, requêtes, réponses, sessions, vues ; il apporte [Werkzeug] (requêtes HTTP, serveur de développement), [Jinja2] (les vues) et [itsdangerous] (les signatures)
3.1.3
[asgiref]
les actions asynchrones ([async def]), installé par [Flask[async]] (exemple 03)
3.12.1
[Pydantic]
la liaison et la validation des paramètres des actions (chapitre 3)
2.13.5
[email-validator]
la validation des adresses électroniques, pour [Pydantic] et [WTForms]
2.3.0
[Flask-WTF]
les formulaires HTML ([WTForms]) et la protection anti-CSRF (chapitre 4)
1.3.0
[Babel]
le formatage des dates et des montants selon la langue (chapitres 3 et 4)
2.18.0
[PyJWT]
les jetons JWT (chapitre 8)
2.15.0
[bcrypt]
le hachage des mots de passe (chapitre 8)
5.0.0
[SQLAlchemy]
l'ORM, l'accès à la base de données (chapitre 9)
2.1.1
[PyMySQL]
le pilote [MySQL], écrit en [Python] (chapitre 9)
1.2.3
[Waitress]
un serveur web de production (étude de cas)
3.0.2

1.3. Exécuter l'étude de cas

Note du réviseur : je conseille au lecteur d'exécuter immédiatement l'étude de cas comme il est indiqué dans ce qui suit. Une fois bien compris le rôle de cette application de rendez-vous, demander à son IA favorite de modifier l'application dans le sens suivant : désormais chaque médecin pourra :

  • fixer lui-même les créneaux de consultation entre deux dates. Cela lui permettra de modifier ses horaires selon ses besoins ;
  • supprimer dans l'agenda d'un jour donné certains créneaux : indisponible pour raisons personnelles par exemple ;

La modification n'est pas simple parce qu'elle implique un changement de structure de la base de données. Demandez à l'IA de vous fournir le nouveau code de l'application et le script SQL pour créer la nouvelle base de données. Pour cela, vous aurez besoin de lui fournir le zip du projet complet ainsi que le script SQL de l'ancienne base de données.

Par ailleurs, je n'ai pas révisé le cours produit par Claude. Il avait déjà produit des cours [NestJS], [ASP.NET Core MVC] et [Spring MVC] parfaits. J'ai supposé qu'il en était de même pour celui-ci. Si vous butez sur un obstacle de compréhension, la solution est toujours la même : demandez à votre IA favorite de vous expliquer ce que vous ne comprenez pas. Claude, par exemple, fait ça très bien. Vous aurez peut-être besoin de lui "uploader" l'exemple que vous ne comprenez pas.

Fin de note.

L'étude de cas qui termine ce document est une application complète. Le lecteur voudra sans doute la voir fonctionner avant d'entrer dans le détail du framework : voici comment l'exécuter. Elle se trouve dans le dossier [rdvmedecins2-flask], à côté du dossier [exemples] :

1
2
3
flask-sept-2026/
├── exemples/
└── rdvmedecins2-flask/

Il faut avoir installé [Python] (3.12 ou plus récent), [Visual Studio Code] et [MySQL] (cf. annexes). Puis :

  • créer la base de données [dbrdvmedecins2], en exécutant le script [rdvmedecins2-flask/database/dbrdvmedecins2.sql]. Avec [Laragon], on ouvre l'outil [HeidiSQL] (bouton Base de données), puis on exécute le script par le menu Fichier / Exécuter un fichier SQL. En ligne de commande, depuis le dossier [rdvmedecins2-flask] :
mysql -u root < database/dbrdvmedecins2.sql
  • ouvrir le dossier [rdvmedecins2-flask] dans [Visual Studio Code] (menu Fichier / Ouvrir le dossier), puis un terminal (menu Terminal / Nouveau terminal) ;
  • créer l'environnement virtuel de l'application, et l'activer. Un environnement virtuel est un dossier (ici [.venv]) qui contient une copie de l'interpréteur [Python] et les bibliothèques d'un projet, et d'elles seules : chaque projet a les siennes, dans les versions qui lui conviennent, sans interférer avec les autres projets de l'ordinateur. Sous [Windows] (invite de commandes ou terminal de [Visual Studio Code]) :
python -m venv .venv
.venv\Scripts\activate

et sous [Linux] et [macOS] :

python3 -m venv .venv
source .venv/bin/activate
  • une fois l'environnement activé, l'invite du terminal commence par [(.venv)], et les commandes [python] et [pip] sont celles de l'environnement. Sous [Windows], le terminal [PowerShell] refuse parfois d'exécuter le script d'activation (message « l'exécution de scripts est désactivée sur ce système ») : la commande [Set-ExecutionPolicy -Scope CurrentUser RemoteSigned], tapée une fois pour toutes, l'autorise. [Visual Studio Code] détecte l'environnement et propose de l'utiliser pour le projet : il faut accepter (on peut aussi le choisir par la commande Python: Select Interpreter, touches Ctrl-Maj-P) ; les terminaux ouverts ensuite l'activent d'eux-mêmes ;
  • installer les bibliothèques de l'application, dans l'environnement virtuel :
pip install -r requirements.txt
  • vérifier la connexion à la base. L'application se connecte à [MySQL] sur [localhost], port 3306, avec l'utilisateur [root] sans mot de passe (les réglages par défaut de [Laragon]). Si votre compte [root] a un mot de passe, indiquez-le dans le fichier [config.py] de l'application, à la ligne [DB_PASSWORD = ""] (par exemple [DB_PASSWORD = "monMotDePasse"]). Pour ne pas écrire de mot de passe dans un fichier du projet, on peut aussi le donner dans la variable d'environnement [FLASK_DB_PASSWORD], qui l'emporte sur le fichier : [set FLASK_DB_PASSWORD=monMotDePasse] sous [Windows] (invite de commandes), [$env:FLASK_DB_PASSWORD="monMotDePasse"] sous [PowerShell], [export FLASK_DB_PASSWORD=monMotDePasse] sous [Linux] et [macOS] ;
  • lancer l'application (sous [Linux] et [macOS], [python3] si [python] n'existe pas) :
python app.py
  • l'application lit la base, puis démarre le serveur de développement de [Flask]. La console affiche les ordres SQL envoyés à la base (nous n'en reproduisons que les principaux), puis les messages du serveur :
... INFO sqlalchemy.engine.Engine BEGIN (implicit)
... INFO sqlalchemy.engine.Engine SELECT medecins.titre, medecins.nom, medecins.prenom, ... FROM medecins LEFT OUTER JOIN users AS users_1 ON users_1.id = medecins.user ORDER BY medecins.nom, medecins.prenom
... INFO sqlalchemy.engine.Engine ROLLBACK
... INFO sqlalchemy.engine.Engine BEGIN (implicit)
... INFO sqlalchemy.engine.Engine SELECT clients.titre, clients.nom, clients.prenom, ... FROM clients LEFT OUTER JOIN users AS users_1 ON users_1.id = clients.user ORDER BY clients.nom, clients.prenom
... INFO sqlalchemy.engine.Engine ROLLBACK
 * Serving Flask app 'rdvmedecins'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:8081
Press CTRL+C to quit
 * Restarting with stat
 ... (les mêmes ordres SQL)
 * Debugger is active!
 * Debugger PIN: 332-612-699

Chaque ligne de [SQLAlchemy] commence par la date et l'heure (remplacées ici par [...]). On y lit que l'application a lu la liste des médecins et des clients (les deux requêtes SQL), que le serveur écoute sur le port 8081 de l'adresse [127.0.0.1] (c'est-à-dire [localhost]), et qu'il fonctionne en mode debug (développement) : l'application redémarre d'elle-même dès qu'un fichier [Python] est modifié ([Restarting with stat] : le processus qui surveille les fichiers relance l'application, qui relit la base), et une erreur inattendue affiche une page de débogage (le « PIN » protège la console de cette page). L'avertissement rappelle que ce serveur est fait pour le développement, pas pour la production (l'étude de cas explique comment utiliser un serveur de production) ;

  • ouvrir l'adresse [http://localhost:8081] dans un navigateur :

Image

  • se connecter avec l'un des comptes de démonstration, dont le mot de passe est le login : [admin] (administrateur), [pelissier], [tatou], [dupont] (médecins), [martin], [durand], [bistrou], [german] (patients). Il faut aussi recopier les caractères de l'image, en majuscules ou en minuscules.

Au démarrage, l'application lit la base : si [MySQL] est inaccessible, elle s'arrête aussitôt, et la console indique pourquoi, à la fin d'un long message d'erreur (avant la ligne « Background on this error »). Avec le message [Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)] (ou [[WinError 10061]] sous [Windows]), c'est que [MySQL] n'est pas démarré ; avec [Access denied for user 'root'@'localhost'], que le mot de passe est incorrect ; avec [Unknown database 'dbrdvmedecins2'], que le script SQL n'a pas été exécuté ; avec [ModuleNotFoundError: No module named 'flask'], que l'environnement virtuel n'est pas activé (ou que les bibliothèques n'y ont pas été installées) ; avec [Address already in use] (ou [Port 8081 is in use by another program]), que le port 8081 est déjà occupé (par la version [Spring MVC] de l'application, par exemple). Le fichier [README.md] de l'application décrit d'autres cas. On arrête l'application par [Ctrl-C] dans le terminal.

L'étude de cas, à la fin du document, présente l'utilisation de l'application, puis commente chacun de ses fichiers.

1.4. Les exemples

Les exemples sont rangés dans le dossier [exemples], un sous-dossier par exemple :

1
2
3
4
5
6
7
8
exemples/
├── 01-structure/
├── 02-routage/
├── ...
├── 28-couches/
├── commun/
│   └── bootstrap/
└── requirements.txt

Chaque exemple est une petite application [Flask], que l'on exécute seule. Tous les exemples utilisent les mêmes bibliothèques, décrites par le fichier [exemples/requirements.txt] :

# les bibliothèques des exemples : pip install -r requirements.txt
# (les versions avec lesquelles les exemples ont été écrits et testés)
Flask[async]==3.1.3
Flask-WTF==1.3.0
email-validator==2.3.0
pydantic==2.13.5
Babel==2.18.0
PyJWT==2.15.0
bcrypt==5.0.0
SQLAlchemy==2.1.1
PyMySQL[rsa]==1.2.3
  • ligne 3 : [Flask], et ce qu'il faut pour écrire des actions asynchrones (l'extra [[async]], qui ajoute la bibliothèque [asgiref], cf. exemple 03) ;
  • lignes 4-7 : les formulaires, la validation, le formatage selon la langue ;
  • lignes 8-9 : l'authentification (chapitre 8) ;
  • lignes 10-11 : l'accès à la base de données (chapitre 9). L'extra [[rsa]] de [PyMySQL] ajoute la bibliothèque [cryptography], nécessaire pour se connecter à un serveur [MySQL] 8 avec un compte protégé par mot de passe.

Chaque ligne a la forme [nom==version] : l'opérateur [==] demande exactement cette version, celle avec laquelle les exemples ont été testés. On pourrait être moins exigeant ([Flask>=3.1] : la version 3.1 ou une plus récente) ; mais une version future d'une bibliothèque peut changer un comportement, et un cours doit pouvoir être reproduit à l'identique. Les lignes qui commencent par [#] sont des commentaires.

Pour exécuter les exemples, on crée d'abord, une fois pour toutes, l'environnement virtuel des exemples, dans le dossier [exemples] (cf. l'étude de cas pour les détails) :

1
2
3
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt

([source .venv/bin/activate] sous [Linux] et [macOS]). Le dossier [commun/bootstrap] contient le framework CSS [Bootstrap], partagé par les exemples qui mettent leurs pages en forme (à partir de l'exemple 15).

Les exemples ont presque tous la même structure. Par exemple, celui de l'exemple 13 :

13-premiere-vue/
├── controllers/
│   ├── __init__.py
│   └── vues.py
├── models/
│   ├── __init__.py
│   └── page.py
├── templates/
│   └── vues/
│       ├── index.html
│       └── inconnu.html
└── app.py
  • [app.py] : le fichier de démarrage de l'application, que l'on exécute ; il construit l'application et lance le serveur (cf. exemple 01) ;
  • [controllers] : les contrôleurs, c'est-à-dire les fichiers qui contiennent les actions. C'est un paquet [Python] : un dossier qui contient des modules (des fichiers [.py]), et que l'on peut importer ([from controllers.vues import vues]). Le fichier [__init__.py], ici vide, fait du dossier un paquet (il est exécuté à la première importation du paquet) ;
  • [models] : les classes qui décrivent les modèles (des actions et des vues) ;
  • [templates] : les vues [Jinja2] (à partir du chapitre 4). [Flask] les cherche dans ce dossier, à côté du fichier de l'application ;
  • [static] (à partir de l'exemple 15) : les fichiers envoyés tels quels au navigateur (feuilles de style, images, scripts [JavaScript]).

Pour exécuter un exemple, on ouvre un terminal sur son dossier (dans [Visual Studio Code] : clic droit sur le dossier de l'exemple, puis Ouvrir dans le terminal intégré), on active l'environnement virtuel des exemples s'il ne l'est pas déjà ([..\.venv\Scripts\activate] sous [Windows], [source ../.venv/bin/activate] sous [Linux] et [macOS] : l'environnement se trouve dans le dossier [exemples], parent du dossier de l'exemple), et on tape :

python app.py

Tous les exemples écoutent sur le port 5000 : on ne peut en exécuter qu'un à la fois. On arrête le serveur par [Ctrl-C] dans le terminal. Sous [macOS], le port 5000 est parfois déjà occupé par le « Récepteur AirPlay » du système (message [Address already in use]) : on le désactive dans Réglages Système / Général / AirDrop et Handoff, ou l'on change le port dans le fichier [app.py] de l'exemple ([port=5001]).

Quand on ouvre le dossier [exemples] dans [Visual Studio Code], l'extension [Python] propose d'utiliser l'environnement [.venv] : on bénéficie alors, dans chaque fichier, de la coloration syntaxique, de la complétion et du signalement des erreurs. Chaque exemple est lancé depuis son propre dossier : c'est pourquoi les importations d'un exemple ([from controllers.vues import vues]) partent de ce dossier. [Pylance], qui analyse le code depuis le dossier ouvert ([exemples]), peut alors souligner ces importations en les disant introuvables : c'est sans conséquence sur l'exécution. Pour que [Pylance] les trouve, il suffit d'ouvrir le dossier de l'exemple lui-même (menu Fichier / Ouvrir le dossier). Enfin, tous les exemples sont lancés en mode debug (cf. exemple 01) : une application lancée redémarre toute seule, en une seconde environ, dès que l'un de ses fichiers [Python] est modifié et enregistré.

Les exemples qui utilisent [Bootstrap] le trouvent dans le dossier [commun/bootstrap], et non dans leur propre dossier : le fichier n'existe ainsi qu'en un exemplaire. Chacun de ces exemples le sert sous l'URL [/bootstrap/...], par quelques lignes de son fichier [app.py]. Par exemple [15-gabarit/app.py] :

# app.py : l'application de l'exemple 15
from datetime import date
from pathlib import Path

from flask import Blueprint, Flask, request

from controllers.pages import pages

# Bootstrap, partagé par les exemples : le dossier exemples/commun/bootstrap,
# désigné à partir de l'emplacement de CE fichier (et non du dossier courant)
BOOTSTRAP = Path(__file__).resolve().parent.parent / "commun" / "bootstrap"


def create_app():
    app = Flask(__name__)
    app.jinja_env.trim_blocks = True
    app.jinja_env.lstrip_blocks = True
    # un blueprint sans route, qui ne sert que des fichiers statiques : le
    # dossier BOOTSTRAP, sous l'URL /bootstrap/...
    app.register_blueprint(Blueprint("bootstrap", __name__, static_folder=BOOTSTRAP,
                                     static_url_path="/bootstrap"))
    app.register_blueprint(pages)
  • ligne 11 : le chemin du dossier [commun/bootstrap]. [__file__] est le chemin du fichier en cours d'exécution ([app.py]) ; [Path(...).resolve()] en fait un chemin absolu ; [.parent] désigne le dossier qui le contient ([15-gabarit]), et [.parent.parent] le dossier au-dessus ([exemples]). L'opérateur [/] d'un objet [Path] ajoute un élément au chemin, avec le bon séparateur ([\] sous [Windows], [/] ailleurs). Le chemin ne dépend donc pas du dossier courant : l'exemple trouve [Bootstrap] d'où qu'on le lance ;
  • lignes 20-21 : un blueprint est un groupe de routes, enregistré dans l'application (cf. exemple 02). Celui-ci n'a pas de route : il ne sert qu'à publier le dossier [commun/bootstrap] (paramètre [static_folder]) sous l'URL [/bootstrap] (paramètre [static_url_path]). Une page peut ainsi utiliser la feuille de style [/bootstrap/css/bootstrap.min.css].

Les autres lignes de ce fichier seront expliquées avec l'exemple 15.

1.5. Contenu du document

Le document progresse ainsi :

Chapitre
Contenu
Exemples
Actions, routage, réponses
de la requête à l'action : routes, blueprints, réponses, redirections, services partagés
01 à 06
Le modèle d'une action
les paramètres de la requête : liaison, conversion, validation avec [Pydantic], formulaires POST
07 à 12
La vue et son modèle
[Jinja2], gabarit, macros, formulaires [WTForms], validation, PRG, protection anti-CSRF
13 à 21
Internationalisation
une application en français et en anglais
22
Portées des données
application, requête, session, client
23
Le cycle de vie d'une requête
middleware WSGI, [before_request], [after_request], [teardown_request], convertisseurs, gestionnaires d'erreurs
24
Authentification et autorisation
JWT dans un cookie, décorateurs, rôles, captcha, limitation des tentatives
25 à 27
Architecture en couches
web / métier / DAO avec [SQLAlchemy] et [MySQL]
28
Étude de cas
l'application RdvMedecins, commentée fichier par fichier
-

Chaque exemple introduit peu de nouveautés, et les chapitres s'appuient les uns sur les autres : il est préférable de les lire dans l'ordre. L'étude de cas, elle, réutilise toutes les notions des chapitres précédents : chaque fois que c'est utile, son commentaire renvoie à l'exemple où la notion a été présentée. Les annexes décrivent l'installation des outils : [Python], [Visual Studio Code] et son extension [Python], [MySQL] avec [Laragon], et [curl].