Accueil

Traduction

Tutoriel Python - sommaire

Tutoriel Python - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Flask : templates avec formulaires

Un template peut contenir un formulaire HTML afin que l'internaute puisse effectuer des saisies.

Comme vous savez sans doute, les données saisies via un formulaire peuvent être envoyées selon la méthode GET ou selon la méthode POST.
Dans les deux premières applications j'utilise la méthode GET et pour la dernière la méthode POST car les données sont sensibles et ne doivent pas apparaitre dans la barre d'URL.

Rappels sur les formulaires

Pour aborder correctement ce chapitre vous devez maitriser la syntaxe HTML relatives aux formulaires et entre autres tous les types de contrôles y compris les nouveaux introduits par la norme HTML5. Ainsi pour saisir des nombres les nouveaux types de INPUT (number, range) sont très intéressants.

Application "calculette"

Vous devez réaliser une calculatrice en ligne.
Cette application comprend un script et un template (en entrée et en sortie)
Comme les données qui transitent n'ont aucun caractère confidentiel, les soumissions se feront avec la méthode GET ; les données envoyées apparaitront dans la barre d'URL.

Créez un nouveau dossier à la racine de C: et nommez le "flask_calculette".
À la racine de ce dossier créez un sous répertoire "templates" (le nom "templates" est obligatoire).

Le fichier "calculette.py"

C'est la composante "vues" de l'application.
Ce script est stocké à la racine de "c:\flask_calculette".

# script de l'application flask_calculette
# nom du script : calculette.py

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/')
def index():
    return render_template ("calculette.htm")

@app.route('/traitement' , methods = ['GET'])
def traitement():
    try:
        donnees = request.args
        n1 = donnees.get('n1')
        n2 = donnees.get('n2')
        ope = donnees.get('ope')
    
        n1=eval(n1)
        n2 =eval(n2)
    
        print(n1, n2, ope)
        if ope =="+" :
            res = n1 + n2
        if ope == "-" :
            res = n1 - n2
        if ope == "*" :
            res = n1 * n2
        if ope == "/" :
            res = n1 / n2
        return render_template("calculette.htm", /
		premier = n1, operation =ope, deuxieme = n2 , resultat = res)
    except: 
        return render_template("calculette.htm", resultat ="Erreur(s) de saisie")

if __name__ == "__main__":
    app.run(debug = True)   

Pour bien comprendre le code de la vue "traitements()" , regardez conjointement cette vue et le formulaire du template.

Notez la "gestion des exceptions". En effet l'usage de champs de type "number" limitent les risques d'erreurs de saisie sauf la division par zéro.
donnees = request.args : récupère les données soumissionnées avec la méthode GET sous forme d'un dictionnaire nommé "donnees" ; les clés du dictionnaire correspondent aux noms des champs du formulaire.
n1 = donnees.get('n1') : récupération dans le dictionnaire "donnees" de la valeur pour la clé 'n1'.
n1=eval(n1) : conversion d'une chaine numérique en flottant
return render_template("calculette.htm", premier = n1, operation =ope, deuxieme = n2 , resultat = res) : notez les passages de paramètre ; création des variables "premier,operation,deuxieme & resultat" dans le template cible.
return render_template("calculette.htm", resultat ="Erreur(s) de saisie") : création de la variable "resultat" dans le template cible.

Le template "calculette.htm"

Ce template doit être impérativement stocké dans le sous-dossier "templates".

Le code (à dérouler)

Analyse

Ce template sert en entrées et en sorties
<form action="/traitement" method="get"> : les données sont adressées à la route "/traitement" donc à la vue associée.
J'utilise des INPUT de type "number" ; dans ce type de champ on ne peut saisir que des nombres. Donc les erreurs de saisie seront limitées.
Attention pour pouvoir saisir des nombres décimaux dans un champ de type number il faut que l'attribut step soit à "any". La valeur par défaut de cet attribut est 1 ; donc si cet attribut est absent on ne peut saisir que des entiers.

Il y a aussi une liste (élément SELECT) qui contient différentes lignes (éléments OPTION). Rappel : lorsque vous cliquez sur une ligne c'est la "value" qui est saisie !
Notez les noms des zones de saisie : n1,ope,n2

{% if resultat %} : la condition signifie "si la variable 'resultat' existe"
La condition doit être encadrée par {% & %}. Jamais d'espace entre { et % et entre % et }
Une instruction {% endif %} est obligatoire pour fermer le bloc.

Le rendu

Application "nombre à trouver"

Thématique

Un nombre entier compris entre 1 et 99 est généré de façon aléatoire (il est masqué, bien sûr).
Le joueur doit deviner ce nombre secret avec le moins d'essais possible (score d'une partie = 10 - nbre d'essais). Donc s'il trouve le nombre secret après 5 essais son score est 10-5 = 5.
Pour sa recherche il est aidé par le message qui apparait après chaque saisie : "L'entier que tu proposes est plus petit que le secret" ou "l'entier que tu proposes est plus grand que le secret".

Rappel du script dans le chapitre 5

from random import *
nbre_secret = randint(1,100)
while True:
    nbre_propose = input('propose un nombre : ')
    if nbre_secret ==int(nbre_propose):
        print ('correct')
        break
    elif nbre_secret > int(nbre_propose):
        print('trop petit')
    else:
        print('trop grand')

Objectif : faire une application web avec flask

Avec cette fois affichage du nombre d'essais réalisés avant d'avoir deviné l'entier.

À la racine de C: créez un nouveau dossier et nommez le "flask_nbre_a_trouver".

Le script "nbre_a_trouver.py"

Attention la composante "vues" est un peu plus délicate car des variables sont manipulées dans les deux vues.

# script de l'application flask_nbre_a_trouver
# nom du script : nbre_a_trouver.py

from flask import Flask, render_template, request
import random

app = Flask(__name__)

@app.route('/')
def index():
    global secret, essais
    secret = random.randint(1,100)
    print('nombre secret : ', secret)
    essais = 0
    return render_template ("nbre_a_trouver.htm")
    
@app.route('/traitement', methods =['GET'])
def traitement():
    donnees = request.args
    saisi = donnees.get('entier')
    saisi = int(saisi)
    if saisi == secret : 
        compare ="ok"
    elif saisi < secret : 
        compare = "-"
            
    elif saisi > secret :
        compare = "+"
    
    global essais
    essais+=1
    return render_template("nbre_a_trouver.htm", tcompare = compare, tsaisi = saisi, tessais = essais)
    
if __name__ == "__main__":
    app.run(debug = True)

Étudiez attentivement la fonction "index()".
Notez l'instruction : global secret, essais
En effet ces deux variables sont définies dans la vue index() mais doivent être aussi manipulées dans la vue traitement(). Il faut donc les déclarer "global".

Étudiez attentivement la vue "traitement()".
Je ne reviens pas sur les deux premières instructions (voir application précédente.
global essais: dans la fonction traitement() il faut incrémenter essais ; pour modifier une variable globale dans une fonction il est nécessaire de la déclarer "global".
return render_template("nbre_a_trouver.htm", fcompare = compare, fsaisi = saisi, fessais = essais):
Notez les variables créées dans le template par passage de paramètres : tcompare,tsaisi,tessais.

Le template "nbre_a_trouver.htm"

Ce template est bien sûr enregistré dans le sous-dossier "templates".

Le code (à dérouler)

Le rendu

Notez le lien qui s'affiche en cas de découverte du nombre secret. Ce lien redirige vers la route "/" . Donc un nouvel entier est généré ; le compteur "essais" est réinitialisé.

Application "espace_perso"

Dans cette application les données à soumissionner sont sensibles. Aussi nous allons utiliser la méthode POST pour la soumission des données.
Il s'agit ici d'une simulation de connexion à son espace personnel. En effet, dans la réalité il faudrait que l'application soit adossée à une base de donnée pour comparer le mot de passe saisi au mot de passe stocké dans la base.
Par ailleurs la fonctionnalité "inscription à un espace perso" n'est pas évoquée...
Un peu de patience, une application web avec base de données est traitée dans ce tuto.

Créez à la racine de C: un nouveau dossier et nommez le "flask_espace_perso". Puis créez dans ce dossier un sous-dossier "templates".
Cette application comprendra trois templates et bien sûr, toujours un script pour "orchestrer" l'application.

Le script nommée "espace_perso.py"

C'est la composante "vues" de cette application.

# nom du script : espace_perso.py
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/')
def index():
    return render_template ("index.htm")

@app.route('/connexion')
def connexion():
   return render_template("connexion.htm")
    
@app.route('/traitement' , methods = ['POST'])
def traitement():
    donnees = request.form
    identifiant = donnees.get('identifiant')
    motpasse = donnees.get('motpasse')
      
   # simulation de récupération dans la base de données du mot de passe pour identifiant saisi
    identifiant_memorise ="dupont@free.fr"
    motpasse_memorise ="sesame62"
	nom_memorise ="Dupont Julien"
    
    if identifiant == identifiant_memorise and motpasse == motpasse_memorise :
        return render_template('traitement.htm', nom_utilisateur = nom_memorise)
    else :
        return render_template("traitement.htm")
   
if __name__ == "__main__":
    app.run(debug = True)

donnees = request.form (et non plus request.args) : récupère les données soumissionnées avec la méthode POST.
identifiant = donnees.get('identifiant') : "donnees" est un dictionnaire ; la méthode get('identifiant') permet de récupérer la valeur de la clé "identifiant".
Rappel : les noms des clés du dictionnaire correspondent aux noms des champs du formulaire.

Le template "index.htm"

Le code ci-dessous (à dérouler)

Notez les liens "morts' sauf le dernier.
Si vous cliquez sur le dernier lien ('Me connecter') le template "connexion.htm" va s'afficher.

Le template "connexion.htm"

Le code ci-dessous (à dérouler)

Tous les templates de cette application ont une feuille de style identique à celle de "index.htm".

<form action="/traitement" method ="post"> : les données soumissionnées avec la méthode "post" sont dirigées vers la route "/traitement".

Le rendu

La barre d'url ne contient que : http://localhost:5000/connexion

Le template "traitement.htm"

Le code ci-dessous (à dérouler)

Notez la syntaxe pour un SI ... ALORS ... SINON dans un template.

Le rendu

Si le mot de passe saisi coïncide avec celui qui est stocké.

Vous pouvez tester en local ces applications web

Afin de vous familiariser avec la syntaxe des templates je vous invite à "uploader" les applications décrites dans ce chapitre.