Ceci est une ancienne révision du document !
Flask
Mini framework pour faire une petite appli web avec des templates, du mail… : https://palletsprojects.com/p/flask/
6 tutos vidéos sympa en français : https://www.youtube.com/playlist?list=PLn6POgpklwWrbGpkwkTS-TvnXxp34srC4
5 autres sur Flask et les formulaireshttps://www.youtube.com/channel/UCABGT_MVqwPXXbdrOO_uYFQ/videos
https://www.tutorialspoint.com/flask/index.htm
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Requêtes query strings, Form Data, Json Data, POST et GET : https://scotch.io/bar-talk/processing-incoming-request-data-in-flask
Exemples de code : https://roytuts.com/category/python/flask/
Créer une appli Flask avec un template jinja2 et quelques routes
myapp.py :
#!/usr/bin/python # -*- coding: Utf-8 -*- from flask import Flask, render_template app = Flask(__name__) @app.route('/') @app.route('/accueil') def index(): # dictionnaire de data mesdata = {'user': 'Xavki', 'machine': 'lubuntu-18.04'} # affichage return render_template('index.html', title='Home', data=mesdata) @app.route('/hello/<string:username>') def bonjour(username): # on oblige username a être une chaine return "Page Hello " + username + " et bonjour !<br/><a href=" + url_for('index') + ">Retour</a>" if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
Dans le sous-dossier “templates”, un fichier index.html
<html> <head> <title>{{ title }} - Microblog</title> </head> <body> <h1>Hello, {{ data.user }}!</h1> <p>Tu es connecté de la machine : {{ data.machine }}</p> </body> </html>
Cas avec un template plus élaboré avec des appels aux librairies plateform (pour OS local) et netifaces (pour interfaces réseau)
On rajoute :
import platform import netifaces data = { 'user': 'Xavki', 'machine': platform.node(), 'os': platform.system(), 'dist': platform.linux_distribution(), 'interfaces': netifaces.interfaces() } @app.route('/pages/a/b/c') def pages(a,b,c): context= {'a':a, 'b':b, 'c':c} return render_template('abc.html', **context}
Et dans le template html :
<p>Machine : {{ data.machine }}</p> <p> Variables de contexte : {{ a }} , {{ b }}, {{ c }}</p> <p>OS : {{ data.os }}</p> <p>Distribution : </p> {% for elem in data.dist %} <p style="padding-left:20px">- {{ elem }}</p> {% endfor %} <p>Interfaces : </p> {% for inter in data.interfaces %} <p style="padding-left:20px">- {{ inter }}</p> {% endfor %} {% if a == 0: %} <p> "a" is null </p> {% else %} <p> "a" is not null </p> {% endif %}
Héritage de Templates jinja
https://jinja.palletsprojects.com/en/2.11.x/
Fichier HTML (base.html) à créer dans un dossier “templates”
Ajouter {% block contenu %}{% endblock %} dans le fichier générique “base.html” qui contient la partie commune.
Et dans chaque fichier HTML (index.html, users.html), insérer par exemple :
{% extends 'base.html' %} {% block contenu } blabla {% endblock %}
Fichiers statiques (images, css)
Création d'un dossier “static” et copie des images et css dedans.
Et dans le template html, l'insérer avec
<img src="{{ url_for('static', filname='monimage.jpg') }}"
Récupération de données par URL (query string)
Ex : https://url/?mavar1=17&mavar2=57 (taille maxi recommandée : 256 caractères)
from flask import request valeur1 = request.args.get('mavar1', 'valeur par défaut') # renvoie None si inexistante : à privilégier valeur2 = request.args.get('mavar2', 'valeur par défaut') valeur3 = request.args['mavar3'] # écriture equivalente mais renvoie erreur 400 si variable inexistante toutesvars = request.args
Récupération de données par POST ou GET
Dans la route de réception, il faut rajouter la méthode autorisée comme 'get' ou 'post'
@app.route('/login', methods=['GET','POST'])
Récupérer les données (passées dans le champ name=mavaleur du formulaire) avec :
valeur1 = request.form.get('mavaleur1') # renvoie None si vide : à privilégier valeur2 = request.form['mavaleur2'] # renvoie erreur 400 si vide
Récupération de données en Json
Cas de Mailgun ou autres webhook. Le Json n'est accessible qu'en POST.
mesdata = request.get_json() framework = mesdata['framework'] if 'language' in mesdata: language = mesdata['language']
request.method vaut 'POST' et peut servir de test d'envoi.
Le résultat du form ou du Json est envoyé dans un dictionnaire {key : value} accessible par print(valeur.get[“key”])
Gestion de hash / password
Vérifie la validité d'un mot de passe à partir du hash
from werkzeug.security import generate_password_hash, check_password_hash motdepasse = 'pbkdf2:sha256:xxxxx' if check_password_hash(motdepasse, password): blabla
Développement - debug
Mode développement pratique pour gérer les modifs en direct et l'accès au mode débug en console :
export FLASK_ENV=development
ou ajouter un .env contenant FLASK_ENV=development
Installer le module python-dotenv
pip install python-dotenv
Et indiquer dans le script python :
from dotenv import load_dotenv, find_dotenv load_dotenv(find_dotenv())
Autre méthodes de Flask
abort : pour retourner un code d'erreur HTTP personnalisé (404, 403, 401…)
redirect : pour rediriger vers une page
Méthode pour parcourir un dossier de fichiers (à détailler)
os.walk(dossier_a_parcourir)
Renvoie : parent, listedossiers (dnames), listefichiers (fnames)
os.path.join(parent,nomfichier)
Méthodes de Logging Flask pour traces
1) Avec une methode dédiée :
https://pypi.org/project/flask-log/
2) Avec la méthode de log de python
https://docs.python.org/3.8/library/logging.html
https://www.askpython.com/python-modules/flask/flask-logging
3) avec la doc Flask (librairie logging)
https://flask.palletsprojects.com/en/1.1.x/logging/?highlight=log
NB : penser à utiliser rsyslog pour rotation des logs.
4) Méthode de systemd (Rom1)
utiliser des print() pour envoyer des messages dans la console comme :
print("Headers : ",request.headers) for key, value in request.form.items(): print(key," : ",value) print("Args : ",request.args)
Et ensuite forcer leur écriture dans le journalctl :
import sys sys.stdout.flush()
Voir ensuite les logs dans journalctl avec :
journalctl -f -u nomduserviceflask.service # -f pour suivi en direct