first comit
This commit is contained in:
256
README.md
Normal file
256
README.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# TP : Galerie d'images (flask)
|
||||
|
||||
## Informations générales
|
||||
|
||||
**Cours** : Python Avancé > Web > Flask \
|
||||
**Objectifs pédagogiques** :
|
||||
- Python avancé : framework Flask pour le développement web
|
||||
- Outils modernes (poetry, PyCharm)
|
||||
- Bonnes pratiques de l'entreprise
|
||||
|
||||
---
|
||||
|
||||
## Prérequis
|
||||
|
||||
### Installation et configuration de l’environnement
|
||||
|
||||
Installer les dépendances avec `poetry install` depuis un terminal PyCharm.
|
||||
|
||||
### Connaissances préalables
|
||||
|
||||
- Connaissances de base en programmation
|
||||
|
||||
---
|
||||
|
||||
## Énoncé
|
||||
|
||||
### Contexte
|
||||
|
||||
L'objectif de ce TP Bonus est de développer une application web simple mais robuste avec le micro-framework Flask.
|
||||
|
||||
Vous êtes invité à lire les premières sections de la [documentation officielle de Flask](https://flask.palletsprojects.com/en/stable/quickstart/) pour vous familiariser avec les concepts de base, avant de commencer le TP.
|
||||
|
||||
Cette application web affichera une galerie d'images à partir de fichiers stockés localement sur le serveur.
|
||||
|
||||
Les images étant fournies par le serveur avec différentes largeurs, cela permettra au client d'optimiser la performance réseau en fonction de la taille de l'image réelle à afficher côté client (navigateur).
|
||||
|
||||
Pour vous concentrer sur la logique métier et le fonctionnement de Flask, une partie significative du code vous est déjà fournie :
|
||||
|
||||
* Les **templates HTML** (`layout.html`, `gallery.html`, `404.html`) qui gèrent l'affichage.
|
||||
* Les **fichiers statiques** (CSS Bootstrap) pour le design, ainsi que les images statiques.
|
||||
* Un module utilitaire `utils.py` contenant une fonction `build_image_structure` qui analyse et structure les données du répertoire contenant les images.
|
||||
* Une suite de **tests automatisés** (`test_app.py`) qui vous permettra de valider votre travail au fur et à mesure.
|
||||
|
||||
Votre mission est de compléter le fichier `src/app/views.py` pour faire le lien entre les requêtes des utilisateurs, les données des images et les templates HTML.
|
||||
|
||||
### Objectifs pédagogiques
|
||||
|
||||
À la fin de ce TP, vous saurez :
|
||||
|
||||
* Créer et organiser des routes (vues) dans une application Flask à l'aide de Blueprints.
|
||||
* Faire le rendu de templates HTML en leur transmettant des données dynamiques (`render_template`).
|
||||
* Gérer les erreurs de manière élégante (`try...except`) pour rendre une application plus robuste.
|
||||
* Créer un premier endpoint d'API simple qui retourne des données au format JSON.
|
||||
* Utiliser une suite de tests (Pytest) pour guider et valider votre développement (approche TDD-lite).
|
||||
* Lancer et déboguer une application Flask localement.
|
||||
|
||||
### Mise en place
|
||||
|
||||
Le projet utilise `poetry` pour la gestion des dépendances.
|
||||
|
||||
La structure du projet est la suivante :
|
||||
|
||||
```
|
||||
.
|
||||
├── poetry.lock
|
||||
├── pyproject.toml
|
||||
├── src
|
||||
│ └── app
|
||||
│ ├── __init__.py # Point d'entrée de l'application
|
||||
│ ├── static/ # Fichiers CSS, et images
|
||||
│ ├── templates/ # Fichiers HTML (templates Jinja2)
|
||||
│ ├── utils.py # Fonctions utilitaires (fourni)
|
||||
│ └── views.py # Le fichier à compléter !
|
||||
└── tests
|
||||
└── test_views.py # Tests pour valider votre code (fourni)
|
||||
```
|
||||
|
||||
### Travail à réaliser
|
||||
|
||||
Ouvrez le fichier `src/app/views.py`. Il est actuellement presque vide. Vous allez le compléter étape par étape.
|
||||
|
||||
#### Étape 1 : afficher la galerie d'images
|
||||
|
||||
Votre premier objectif est de créer la vue principale qui affiche la galerie.
|
||||
|
||||
**Tâche :** Créez une fonction `index()` qui répond à la route `/` (la racine du site).
|
||||
|
||||
**Logique à implémenter dans la fonction `index()` :**
|
||||
|
||||
1. Construisez le chemin vers le dossier contenant les images. Ce dossier se trouve dans `static/images`. Utilisez `current_app.static_folder` de Flask et la bibliothèque `pathlib` pour un code propre et portable.
|
||||
|
||||
2. Appelez la fonction `build_image_structure()` (importée depuis `.utils`) en lui passant le chemin du dossier des images.
|
||||
|
||||
3. **Rendez votre code robuste !** Encadrez l'appel à cette fonction dans un bloc `try...except`. En cas d'erreur (par exemple, si le dossier n'existe pas ou si un autre problème survient), vous devez éviter que l'application ne plante.
|
||||
|
||||
* En cas de succès, vous passez les données des images au template.
|
||||
|
||||
* Si aucune image n'est trouvée par la fonction, prévoyez un message d'erreur à afficher.
|
||||
|
||||
* En cas d'exception, logguez l'erreur et préparez un message d'erreur générique pour l'utilisateur.
|
||||
|
||||
4. Faites le rendu du template `gallery.html` en utilisant `render_template()`. Vous devez lui passer deux variables :
|
||||
|
||||
* `structured_images`: Le dictionnaire d'images retourné par `build_image_structure`.
|
||||
|
||||
* `error_message`: Un message d'erreur (ou `None` si tout va bien).
|
||||
|
||||
**Diagramme de flux (Étape 1) :**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Client[Navigateur]
|
||||
A[Utilisateur]
|
||||
end
|
||||
subgraph Serveur[Serveur Flask]
|
||||
B["Route /"]
|
||||
C["views.py: index()"]
|
||||
D["utils.py: build_image_structure()"]
|
||||
E["templates/gallery.html"]
|
||||
F[Réponse HTML]
|
||||
end
|
||||
subgraph SystemeFichiers[Disque Serveur]
|
||||
G["static/images"]
|
||||
end
|
||||
|
||||
A -- "1. Requête GET /" --> B
|
||||
B -- "2. Déclenche" --> C
|
||||
C -- "3. Construit chemin et appelle" --> D
|
||||
D -- "4. Lit le dossier" --> G
|
||||
G -- "5. Retourne la structure" --> D
|
||||
D -- "6. Retourne dict_images" --> C
|
||||
C -- "7. Injecte données dans" --> E
|
||||
E -- "8. Génère" --> F
|
||||
F -- "9. Envoie" --> A
|
||||
```
|
||||
|
||||
**Logique de gestion d'erreur (commune aux étapes 1 et 4) :**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Début de la vue] --> B{try}
|
||||
B -- "Succès" --> C["Appel: build_image_structure()"]
|
||||
C --> D{Images trouvées?}
|
||||
D -- "Oui" --> E[Préparer réponse 200 OK - HTML ou JSON]
|
||||
D -- "Non" --> F[Préparer réponse - HTML avec erreur ou JSON 404]
|
||||
B -- "Échec" --> G[except Exception as e]
|
||||
G --> H[Logguer l'erreur e]
|
||||
H --> I[Préparer réponse - HTML avec erreur ou JSON 500]
|
||||
E --> Z[Fin]
|
||||
F --> Z[Fin]
|
||||
I --> Z[Fin]
|
||||
```
|
||||
|
||||
#### Étape 2 : valider avec les tests
|
||||
|
||||
Avant même de regarder le résultat dans votre navigateur, vérifiez que votre code est correct en lançant la suite de tests.
|
||||
|
||||
```bash
|
||||
poetry run pytest -p no:warnings
|
||||
```
|
||||
|
||||
Analysez le résultat. Certains tests qui échouaient au début devraient maintenant passer. L'objectif est de faire passer tous les tests relatifs à la galerie.
|
||||
|
||||
#### Étape 3 : lancer le serveur et constater le résultat
|
||||
|
||||
Une fois les tests au vert, lancez le serveur de développement Flask.
|
||||
|
||||
1. Assurez-vous d'être dans le bon dossier :
|
||||
|
||||
```bash
|
||||
cd src
|
||||
```
|
||||
|
||||
2. Lancez le serveur en mode "debug" (ce mode recharge automatiquement le serveur à chaque modification de votre code) :
|
||||
|
||||
```bash
|
||||
flask run --debug
|
||||
```
|
||||
|
||||
3. Ouvrez votre navigateur à l'adresse [http://127.0.0.1:5000](http://127.0.0.1:5000) et admirez votre galerie !
|
||||
|
||||
#### Étape 4 : créer un endpoint d'API JSON
|
||||
|
||||
Votre second objectif est de fournir les mêmes données via une API, au format JSON.
|
||||
|
||||
**Tâche :** Créez une fonction `api_images()` qui répond à la route `/api/images`.
|
||||
|
||||
**Logique à implémenter :**
|
||||
|
||||
1. La logique de récupération des données est la même que pour la vue `index()` : chemin du dossier, appel à `build_image_structure()`, gestion des exceptions.
|
||||
|
||||
2. La différence réside dans la réponse :
|
||||
|
||||
* En cas de succès, retournez directement le dictionnaire `structured_images`. Flask le convertira automatiquement en une réponse JSON avec un code de statut `200 OK`.
|
||||
|
||||
* Si aucune image n'est trouvée, retournez un dictionnaire d'erreur (ex: `{'error': "Aucune image n'a été trouvée"}`) et le code de statut `404 Not Found`.
|
||||
|
||||
* En cas d'exception serveur, retournez un dictionnaire d'erreur (ex: `{'error': "Erreur interne du serveur"}`) et le code de statut `500 Internal Server Error`.
|
||||
|
||||
**Diagramme de flux (Étape 4) :**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Client[Client API ex: Postman, script]
|
||||
A[Utilisateur/Service]
|
||||
end
|
||||
subgraph Serveur[Serveur Flask]
|
||||
B[Route /api/images]
|
||||
C["views.py: api_images()"]
|
||||
D["utils.py: build_image_structure()"]
|
||||
E[Réponse JSON]
|
||||
end
|
||||
subgraph SystemeFichiers[Disque Serveur]
|
||||
G["static/images"]
|
||||
end
|
||||
|
||||
A -- "1. Requête GET /api/images" --> B
|
||||
B -- "2. Déclenche" --> C
|
||||
C -- "3. Construit chemin et appelle" --> D
|
||||
D -- "4. Lit le dossier" --> G
|
||||
G -- "5. Retourne la structure" --> D
|
||||
D -- "6. Retourne dict_images" --> C
|
||||
C -- "7. Formate en JSON" --> E
|
||||
E -- "8. Envoie" --> A
|
||||
```
|
||||
|
||||
#### Étape 5 : ajouter un ou plusieurs tests pour l'API
|
||||
|
||||
Pour aller plus loin, ouvrez le fichier `tests/test_app.py` et ajoutez un ou plusieurs nouveaux tests pour votre API.
|
||||
|
||||
**Idée de test :**
|
||||
Créez une fonction `test_api_images_success()` qui :
|
||||
|
||||
1. Fait un `GET` sur `/api/images`.
|
||||
|
||||
2. Vérifie que le code de statut est bien `200`.
|
||||
|
||||
3. Vérifie que le `content_type` de la réponse est bien `application/json`.
|
||||
|
||||
4. Vérifie que la réponse JSON contient des clés attendues (par exemple, le nom d'une des images).
|
||||
|
||||
Relancez les tests pour vous assurer que l'ancien et le nouveau code fonctionnent parfaitement.
|
||||
|
||||
### Bonnes pratiques
|
||||
|
||||
* La page d'accueil (`/`) s'affiche correctement avec les images. Les images téléchargées par le navigateur sont cohérentes avec la taille réelles des images à afficher.
|
||||
|
||||
* La page gère correctement l'absence du dossier d'images sans planter, en affichant un message d'erreur.
|
||||
|
||||
* L'endpoint `/api/images` retourne une structure JSON valide en cas de succès.
|
||||
|
||||
* L'endpoint `/api/images` retourne les codes d'erreur HTTP et les messages appropriés (404, 500).
|
||||
|
||||
* L'ensemble des tests fournis (et les vôtre) passent avec succès.
|
||||
|
||||
* Le code dans `views.py` est clair, commenté et suit les bonnes pratiques Python.
|
||||
Reference in New Issue
Block a user