Flask est un framework qui simplifie le développement d’interface HTML des projets Python. Flask permet de gérer très facilement les interactions entre le code Python et les actions de l’utilisateur sur l’interface rendant inutile le code Javascript et jQuery.
Flask est une solution industrielle robuste et performante que l’on pourra utiliser sans hésiter pour des projets d’envergure.
Sommaire
Remarque avant de commencer
Il faut arrêter “proprement” le serveur Flask avant de lancer un nouveau script à l’aide de la combinaison de touche Ctrl + C que ce soit dans le Terminal ou Thonny Python IDE.
Si vous quittez l’éditeur de code ou tentez le lancer un script sans arrêter le précédant, vous obtiendrez l’erreur oserror: [errno 98] address already in use flask qui indique qu’un processeur est encore en cours de fonctionnement.
Si c’est le cas, suivez la procédure décrite dans ce paragraphe pour “tuer” celui-ci.
Installer la librairie Python3 Flask
La librairie Flask nécessite Python 3.5 ou supérieur. La version Desktop de Raspberry Pi OS est installée avec les versions 2.7 et 3.7 ou ultérieures. Pour vérifier que la version 3 est bien installée, exécutez la commande suivante dans un Terminal.
Si Python3 est correctement installé, vous devez obtenir le numéro de version en réponse.
python3 --version
Python 3.7.3
Pour installer les librairies Python, il est plus facile d’utiliser le script pip3. Pour vérifier que le script pip3 est bien installé sur Raspberry Pi OS, exécuter cette commande qui doit vous renvoyer le chemin vers le script
pip3 --version
pip 18.1 from /usr/lib/python3/dist-packages/pip (python 3.7)
Si pip3 n’est pas installé, exécuter
sudo apt install python3-pip
Maintenant, on peut installer Flask
python3 -m pip install Flask
Premier serveur Python avec Flask
Lancez Thonny Python IDE depuis le menu Programmation
Coller le code ci-dessous
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello World!"
app.run(debug = True)
Enregistrer le script puis lancer le à l’aide de la flèche verte
Par défaut, le serveur Flask est accessible sur le port 5000
Serving Flask app "1 first flask app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 275-643-102
Cliquer sur le lien ou ouvrir Chromium puis saisir http://127.0.0.1:5000/ dans la barre d’adresse.
Vous devez obtenir cette page
Explication du code
app est le nom de l’application Flask
app = Flask(__name__)
Pour pouvoir accéder au serveur, on doit définir des routes. Ici, on pointe simplement vers la racine du site à l’aide du caractère /
Le décorateur @ permet de spécifier un endpoint et la fonction (immédiatement après) à exécuter dès que la page est appelée par l’utilisateur. Ici la méthode home renvoie simplement une chaîne de texte. Dans une application réelle, la méthode pourra renvoyer une page HTML construite à partir d’une chaîne ou un fichier HMTL standard.
@app.route("/")
def home():
return "Hello World!"
A la fin du script, on démarre le serveur web avec l’option de déboggage.
app.run(debug = True)
Renvoyer du code HMTL
Allons plus loin maintenant en renvoyant du code HTML.
Le rendu des pages HTML peut être fait de 3 manières avec Flask
- return renvoie directement une chaîne contenant le code HMTL de la page. Il faut réserver cette solution aux pages avec peu de code HTML ou les petits projets.
- render_template_string le rendu de la page Web est fait à partir dans une chaîne de caractères stockée directement dans le code Python. Idem
- render_template le rendu de la page Web est fait à partir d’un fichier HTML stocké dans un fichier séparé
Directement dans le code
Cette première version renvoi directement le code HTML de la page sous la forme d’une chaîne
from flask import Flask app = Flask(__name__) @app.route("/") def home(): return "\ \ My First Flask App\ \ " app.run(debug = True)
Le code HTML est constitué de plusieurs lignes. Chaque ligne du code HTML doit se terminer par le caractère \ afin de pouvoir être concaténer par l’interpréteur Python.
A l’aide de la méthode render_template_string
On importe la méthode render_template_string au début du code
La variable HTML_PAGE contient le code HTML de la page sous la forme d’une chaîne encadrée par ”’. Chaque ligne doit se terminer par \.
from flask import Flask, render_template_string app = Flask(__name__) HTML_PAGE = ''' \ \ My First Flask App\ \ ''' @app.route("/") def home(): return render_template_string(HTML_PAGE) app.run(debug = True)
A l’aide de la méthode render_template
Voyons maintenant comment générer un page Web à partir d’un fichier HTML séparé.
Les fichiers HTML doivent être stockés dans un dossier nommé templates situé à la racine du projet. Il est possible de créer des sous-dossiers pour organiser les fichiers HTML
app.py
└ templates
└ sous-dossier
└ page.html
Le code source de la page HTML est parfaitement standard
My First Flask App
La méthode render_template prend 2 paramètres
- Le chemin vers la page HTML dans le dossier templates
- Des paramètres passés au code HTML depuis le code Python qui permettra d’actualiser l’affichage (nous verrons plus tard)
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template('sous-dossier/page.html')
app.run(debug = True)
Dans les trois cas, on obtiendra exactement la même page Web.
Renvoyer du code dynamique
Comme nous l’avons vu précédemment, il est possible de passer des arguments à la méthode render_template ce qui va permettre d’actualiser l’affichage de la page
A la manière du framework Angular, Flask embarque un moteur de rendu appelé Jinja2. Jinja2 propose un pseudo langage qui permet de générer la page HTML en fonction de conditions.
Jinja2 évalue les expressions en fonction des paramètres et des valeurs et génère le code HTML correspondant. Il existe plusieurs types de délimiteurs :
- {% … %} pour déclarer une expression
- {{…}} la variable est remplacée par sa valeur
- {# … #} permet d’ajouter des commentaire ou d’empêcher d’inclure la partie du code concernée dans l’HTML final
- # … ## équivalent à {% … %}, un exemple
# for item in seq
# endfor
- {% for item in seq %}
- {{ item }}
{% endfor %}
Voici un exemple ou le libellé de la LED est affiché ON ou OFF en fonction
Jinja2 demo {% if status %}
LED is ON {% else %}
LED is OFF {% endif %}
Ce template affiche l’état de la LED (On ou Off) en fonction du paramètre status.
Le code Python correspondant au Template précédent
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
return render_template('sous-dossier/page.html', status=True)
app.run(debug = True)
Il est possible de passer autant de paramètre qu’on le souhaite en les séparant par une virgule. La valeur peut être de n’importe quel type, y compris un objet JSON.
return render_template('page.html', param1=val1, param2=val2, param3=val3...)
Ajouter un feuille de style CSS
Les feuilles de styles doivent être stockées dans le dossier static situé à la racine du projet (comme les templates)
app.py
├ statics
| └ style.css
├ templates
└ sous-dossier
└ page.html
Ensuite on déclare la feuille de style CSS comme pour n’importe quel autre projet HTML.
Jinja2 demo
{% if status %}
LED is ON {% else %}
LED is OFF {% endif %}
Temperature: {{ temperature }}°C
La feuille de style CSS correspondante
h1 {
font-size: 24px
}
p {
font-size: 14px;
font-weight: 500
}
Lancer le script et actualiser le navigateur
Ajouter la feuille de style Bootstrap
Plutôt que de développer sa propre feuille de style CSS, le plus facile est d’utiliser le projet Bootstrap.
Remplacer le link vers le fichier style.css par celui de Bootstrap. Le lien proposé dans l’exemple correspond à la version 4 de Boostrap. Aller ici pour trouver le lien le plus récent
Maintenant, les balises standards HTML (h1, h2, p, span…) sont automatiquement mises en forme.
Ici, on va créer un ligne (row) constituée de 2 colonnes (col). Dans chaque colonne on insère une carte (card). La première pour l’état de la LED, la seconde pour la température.
Flask Dashboard with Bootstrap ♥
LED State
{% if status %}
ON {% else %}
OFF {% endif %} Temperature
{{ temperature }}°C
Et voilà le rendu obtenu. Le code peut paraitre beaucoup plus complexe, mais ce n’est pas le cas. Avec Bootstrap, la page HTML pourra s’afficher sur n’importe quel navigateur internet, y compris sur un smartphone !
Envoyer des données ou des actions depuis le Dashboard
Dernier point à aborder avant de conclure cette introduction à Flask, comment envoyer des données ou des actions depuis la page HTML.
Le protocole HTTP dispose de plusieurs méthodes pour chaque opérations pouvant être effectuées via des requêtes HTTP.
GET pour récupérer des données coté navigateur internet
POST pour soumettre des données au serveur. Par exemple les champs d’un formulaire, l’appui sur un bouton…
PUT pour actualiser des données dans une base de données
DELETE pour supprimer des données dans une base de données
On utilisera surtout les méthodes GET et POST dans nos projets. Les autres opérations sont plus spécifiques et sont généralement utilisées lorsqu’il faut manipuler des enregistrement dans une base de données.
On envoie les commandes au code Python à l’aide de requêtes HTTP de type POST. Pour cela, il suffit de placer les boutons (un groupe de boutons Bootstrap) dans un Formulaire.
Voici l’exemple d’une page HTML qui permet de sélectionner la distance pour déplacer l’axe d’un moteur de CNC ou d’imprimante 3D.
Distance to move {{distance}} mm 0.1 mm 1 mm 10 mm
Le code Python de la page
from flask import Flask, render_template, redirect, request
app = Flask(__name__)
distance = 0.1
@app.route("/")
def home():
global distance
return render_template('sub-folder/page.html', distance=distance)
@app.route("/setdistance", methods=["POST"])
def setdistance():
global distance
distance = float(request.form["distance"])
print("set distance to", distance)
return redirect(request.referrer)
app.run(debug = True)
Lorsqu’on appui sur un bouton du sélecteur, le formulaire est envoyé au serveur.
Il faut indiquer à Flask que les méthodes POST sont acceptées pour ce endpoint à l’aide de l’option methods. Un endpoint peut accepter plusieurs types de méthodes qui sont indiquées sans un tableau passé en paramètre.
@app.route("/setdistance", methods=["POST"])
La méthode request.form([“nom_element”]) permet de récupérer la valeur sélectionnée (que l’on converti en float ici).
distance = float(request.form["distance"])
Vous avez certainement remarquez l’astuce qui consiste à donner le même nom à tous les boutons du sélecteur ce qui permet de récupérer avec une seule ligne de code la valeur sélectionnée.
On doit toutefois renvoyer une réponse au navigateur qui attend une confirmation du serveur. Pour cela, on utilise la méthode redirect(). La méthode redirect() permet de renvoyer l’utilisateur vers une page de réponse. C’est par exemple ce qui se passe lorsqu’on s’abonne à une lettre d’information.
Ici on va simplement renvoyer vers la page d’origine à l’aide de la fonction request.referrer.
Une petite démo en vidéo
Si le projet vous intéresse, le code est utilisé dans ce tutoriel sur les moteurs pas à pas (Nema)
Erreur oserror: [errno 98] address already in use flask.
Problème Un processus Flask est encore actif ce qui empêche de lancer un nouveau serveur sur le même port.
Remède Ouvrir un Terminal et exécuter la commande suivante pour identifier le processus flask en mémoire qui correspond au script resté actif.
ps -fA | grep python
Localiser l’ID du processus qui correspond à votre script
Puis exécuter la commande kill numero_du_processus pour arrêter le serveur Flask, ici
kill 1013
Mises à jour
21/10/2020 Publication de l’article
- ESP32, broches GPIO et fonctions associées. I/O, PWM, RTC, I2C, SPI, ADC, DAC
- ESP32-CAM. Broches et équipements ESP-EYE, AI Thinker, TTGO T-Camera, M5Stack Timer Camera…
- ESP32-CAM. Quel modèle choisir ? ESP-EYE, AI Thinker, TTGO T-Camera, M5Stack Timer Camera…
- M5Stack Atomic GPS. Tracker ESP32 TinyGPS++, export GPX sur carte SD, visualisation sur Google Maps ou VSCode
- Home Assistant. Installer le snap sur NAS Synology sur une machine virtuelle Ubuntu
Avez-vous aimé cet article ?