technique:python:flask

Ceci est une ancienne révision du document !


Flask

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 %}

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 %}

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') }}"

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

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”])

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

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())

abort : pour retourner un code d'erreur HTTP personnalisé (404, 403, 401…)

redirect : pour rediriger vers une page

os.walk(dossier_a_parcourir)
Renvoie : parent, listedossiers (dnames), listefichiers (fnames)

os.path.join(parent,nomfichier)

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
  • technique/python/flask.1616028146.txt.gz
  • Dernière modification : 2021/03/18 01:42
  • de francoisa