UE5 : Fondamentaux du développement web frontal, niveau 2

Séance 1 : Une première application

  1. Structure applicative
  2. Travail dans un envrionnement virtuel
  3. Installation de Flask
  4. Modularisation
    1. Ecrire un package simple
    2. Ecrire un package avec des modules
    3. Un petit point sur les chemins
  5. Une première application
  6. Complément: les variables d'environnement

Structure applicative

L'ensemble de l'application peut tenir dans un seul fichier Python, mais plus l'application sera grosse, plus ce fichier sera long et illisible. C'est pourquoi Flask propose de découper l'application en sous-modules, ce qui la rend plus lisible.

mon_application/
├── app/
|   ├── __init__.py
|   ├── app.py
|   ├── models/
|   |   ├── __init__.py
|   |   ├── model1.py
|   |   └── model2.py
|   ├── routes/
|   |   ├── __init__.py
|   |   ├── routes1.py
|   |   └── routes2.py
|   ├── templates/
|   |   ├── container.html
|   |   ├── partials/
|   |   |   └── menu.html
|   |   └── pages/
|   |   |   ├── page1.html
|   |   |   └── page2.html
|   ├── statics/
|   |   ├── css/
|   |   |   └── styles.css
|   |   ├── js/
|   |   |   └── script.js
|   |   ├── img/
|   |   |   └── img.png
|   |   ├── data/
|   |   |   └── data.json
|   └── config.py
├── tests/
├── env/
├── .gitignore
├── README.md
├── requirements.txt
└── .env

Passons en revue chaque dossier et chaque fichier:

Travail dans un environnement virtuel

Avant de commencer le développement du projet Flask (ou de tout autre projet), il convient d'installer un environnement virtuel spécifique à ce projet (un vase clos dans lequel seul le projet s'exécutera). Il est courant d'avoir plusieurs projets en cours de développement sur sa machine, or chaque projet peut utiliser des versions différentes des packages Python. Pour éviter les erreurs sur les packages, l'environnement virtuel est essentiel.

Hors d'un environnement, la commande which python indiquera l'installation globale de Python sur la machine.

which python

L'installation d'un environnement virtuel pour un projet Python se fait en plusieurs étapes, et dans le dossier racine de notre projet (voir dans l'arbre ci-dessus où se trouve le dossier env/)/

# dans un terminal, effectuer les étapes suivantes
# installation du package virtualenv, si ce n'est pas déjà fait, dans le Python global de la machine
pip install virtualenv

# on s'assure ensuite que l'on est dans le dossier racine de l'application
pwd
# si ce n'est pas le cas, y aller
cd dossier_racine/

# installation de l'environnement
virtualenv env -p python3

Les étapes d'installation ne sont à réaliser qu'une seule fois. Une fois l'environnement installé, il suffit de l'activer/désactiver au début et à la fin de chaque séance de développement. Les packagaes installés quand on est dans l'environnement resteront dans cet environnement et n'auront pas d'interférence avec le reste de la machine.

# pour activer l'environnement:
# Ubuntu
source env/bin/activate

# Windows
source env/Scripts/activate

# Mac OS
source env/bin/activate

Une fois activé, (env) apparaît au début de chaque ligne du terminal: c'est l'assurance que l'on travaille dans cet environnement. Pour s'assurer définitivement que l'on a bien un Python dédié au projet, on peut relancer un which python.

which python

Pour désactiver l'environnement, il suffit d'exécuter la commande deactivate.

Installation de Flask

Une fois l'environnement activé, nous pouvons installer toutes les librairies dont l'application va avoir besoin, à commencer par Flask.

pip install Flask

La commande vient d'installer Flask et toutes les librairies dont Flask avait besoin:

Successfully installed Flask-2.2.2 Jinja2-3.1.2 MarkupSafe-2.1.1 Werkzeug-2.2.2 click-8.1.3 colorama-0.4.5 importlib-metadata-5.0.0 itsdangerous-2.1.2 zipp-3.9.0

Il est temps de voir ce que contient notre environnement virtuel:

pip freeze

Comme c'est un vase clos, il contient bien uniquement ce que l'on vient d'installer. Cette comande pip freeze est à exécuter régulièrement à la racine de notre application sous la forme pip freeze > requirements.txt de manière à indiquer aux futurs utilisateurs du code quelles dépendances (et quelles versions) sont nécessaires pour faire fonctionner l'application.

La modularisation

Avant d'entamer le développement d'une première application, il faut avoir conscience de la modularisation requise pour une application. Il s'agit du découpage de l'application en de multiples fichiers, pour rendre le code plus lisible et plus cohérent (c'est le principe des templates, des routes, des models, etc. présentés plus haut). Le développement de l'application est en réalité le développement de multiples modules qui, réunis, forment des packages.

Flask est un package, tout comme colorama ou Jinja2 que l'on a importé juste au-dessus avec l'installation de Flask.

Quand nous ferons plus tard from flask import Flask, nous importerons le module principal Flask du package flask. Chaque module contient des variables, des classes et des fonctions, utilisables par conséquent à de multiples endroits dans l'application. Pratique !

Ecrire un package simple

Ecrire un package est très facile, essayons.

# dès lors qu'un fichier __init__.py se trouve dans un dossier, ce dossier devient package
vi exemples/package_simple/un_package/__init__.py
# dans un fichier run.py, situé au-dessus du dossier deveu package, je peux importer mon package et sa variable d'initialisation "une_variable"
vi exemples/package_simple/run.py
# exécutons run.py
python exemples/package_simple/run.py

Pour résumer, un package se compose toujours d'un fichier __init__.py à la racine d'un dossier. Le nom de ce dossier devient le nom de mon package. Ce package peut être importé depuis du code Python situé autre part dans notre application.

| nom_package/
|   |-- __init__.py
| code_appelant_package.py

Ecrire un package avec des modules

Nous l'avons dit plus haut, un package peut avoir plusieurs modules. Ces modules sont un peu comme des tiroirs, où l'on va trier nos fonctions et nos classes.

# on initie toujours notre fichier __init__.py
vi exemples/package_modules/package/__init__.py
# puis on peut créer notre premier module, module1.py, à côté de ce fichier __init__.py
# à l'intérieur de ce module, on définit une classe Module1() qui contient une seule fonction, une_fonction()
vi exemples/package_modules/package/module1.py
# dans le fichier run.py, on peut alors appeler des variables du package, des modules, des classes et des fonctions
python exemples/package_modules/run.py

Décrivons les imports et l'utilisation des classes:

python  exemples/package_modules/run.py

La création et l'utilisation de packages et de modules n'est pas plus compliquée que cela. Pour résumer:

| nom_package/
|   |-- __init__.py
|   |-- module.py
| code_appelant_package_et_module.py

Un petit point sur les chemins

Les appels de packages se font par des chemins puisque ce sont des fichiers. Il pourrait être tentant de donner un chemin depuis la racine de la machine (ce que l'on appele un chemin absolu), mais cela irait à l'enconytre du principe-même de package qui veut que ce package soit partageable et réutilisable sur différentes machines.

Pour éviter de tels problèmes, il conviendra de toujours utiliser les imports relatifs. Pour naviguer dans l'arborescence de l'application, on utilise des .:

Prenons pour exemple le dossier exemples/chemins/. Il comporte deux packages package1 et package2, comprenant chacun deux modules module1 et module2.

| package1/
|   |-- __init__.py
|   |-- module1.py
|   |-- module2.py
| package2/
|   |-- __init__.py
|   |-- module1.py
|   |-- module2.py
| run.py

Première application

Il est temps de créer une première application et de la faire tourner sur notre serveur de développement dans l'environnement virtuel. Pour créer une application fonctionnelle avec Flask, il suffit de quelques lignes dans le fichier run.py.

# Code/Seance1/base/run.py
from flask import Flask

app = Flask(__name__)

app.run()
python run.py

Ces deux lignes suffisent à créer une instance de Flask. Lancer app.run() permet d'exécuter l'application et de la faire tourner sur notre serveur local.

Cette application est très basique, et il vaut mieux la structurer correctement dès le début, en préparant modules et packages. C'est le package Code/seance1/structure

| app/
|   |-- __init__.py
|   |-- app.py
|nom_application.py
# pour lancer l'application, il faut désormais exécuter la commande suivante dans le terminal
python mon_application.py

Le serveur doit se lancer correctement, en indiquant son port d'exécution sur un hôte local. Mais il n'y a pas encore d'URL sur notre application. Ce sera le but de la Séance2.

Complément: les variables d'environnement

Quand on lance le serveur, on remarque une ligne Debug mode: on. Si l'on souhaite changer cette variable, il nous faut modifier une variable d'environnement (DEBUG) sur laquelle s'appuie Flask. Le mode DEBUG se définit lors du lancement de app.run(). Il serait donc tentant de mettre app.run(debug=True). Seulement, cette solution n'est pas idéale quand on partage son code, et surtout, quand nous définirons plus tard des mots de passe, il nous faudra variabiliser notre application. Autant entamer la variabilisation dès maintenant.

Pour cela, il nous faut plusieurs fichiers:

Commençons par .env, ce sont des paires clé=valeur, où la clé est le nom de notre varibale.

# .env
DEBUG=True

Passons ensuite à config.py. Il est nécessaire d'installer python-dotenv avec pip install python-dotenv.

# Code/Seance1/structure/app/config.py
import dotenv
import os

# on récupère le chemin actuel de l'application
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# on charge les varibales de .env
dotenv.load_dotenv(os.path.join(BASE_DIR, '.env'))

class Config():
    DEBUG = os.environ.get("DEBUG")
# Code/Seance1/structure/app/app.py
from .config import Config

...

app.config.from_object(Config)

Dorénavant, les variables d'environnement sont accessibles dans un dictionnaire via app.config["nom_variable"]. On peut donc maintenant lancer l'application avec app.run(app.config["DEBUG"])