TP basé sur la manipulation d'un serveur Flask.
Objectif : visualiser des interactions entre le client et le seveur (qui seront ici une seule et même machine)
Pour simplifier le schéma client-serveur désigne un mode de communication entre programmes : l'un qualifié de client envoie des requêtes; l'autre, le serveur, y répond.
Dans le cas du WEB
, le client est le navigateur et protocole utilisé pour communiquer est HTTP
.
Dans notre TP le client et le serveur seront situés tous les deux sur votre ordinateur.
Il existe de nombreux serveurs web, mais le plus utilisé se nomme Apache. Nous n'allons pas utiliser Apache, car nous allons travailler avec le framework Python Flask.
Un framework, pour simplifier, est un ensemble de logiciels qui serviront d'architecture (ou de base) pour créer un autre logiciel.
Dans notre cas, Flask (module Python) nous permettra de créer notre serveur pour héberger quelques pages rédigées en html et css.
Vous utilisez un navigateur internet pour accéder à ses pages, le navigateur sera donc le ... client ! Bien vu 😉
pip install flask
views.py
(il sera placé dans le répertoire TP_Flask
)from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Salut le monde !"
if __name__ == '__main__':
app.run(debug=True)
python .\views.py
(c'est en fait ce que fait VSC si vous avez installé l'extension Python)http://127.0.0.1:5000/
(ou encore http://localhost:5000/
)Vous devriez obtenir un page html très simple avec un beau message de bienvenue ! 😯
Si cela ne fonctionne pas, contactez votre professeur en notant bien les éventuels message d'erreurs obtenus.
Comment comprendre le code que vous avez utilisé ? 😱 Rassurez-vous, vous devez le comprendre mais pas savoir le produire en partant de rien !
Allons-y étape par étape :
from flask import Flask
Permet d'importer le module flask
app = Flask(__name__)
Créer un objet app : cette ligne est systématique nécessaire.
@app.route('/')
Nous utilisons ici un décorateur (cette notion de décorateur ne sera pas traitée en NSI). Vous devez juste comprendre la fonction qui suit ce décorateur ("index"), sera exécutée dans le cas où le serveur web recevra une requête HTTP avec une URL correspondant à la racine du site ('/'), c'est à dire, dans notre exemple, le cas où on saisie dans la barre d'adresse "127.0.0.1:5000/" ou "localhost:5000/" (ou simplement "localhost:5000")
def index():
return "Salut le monde !"
C'est la fonction qui sera appelée lorsqu'un client demandera l'adresse localhost:5000/
Elle revoie toujours le même contenu, on parlera de contenu "statique". Plus tard nous verrons comment faire évoluer ce contenu en fonction de paramètres.
if __name__ == '__main__':
app.run(debug=True)
Ces 2 lignes permettent d'exécuter le mode "debug". Ces lignes seront nécessaire pour le développement de nos application. Dans la console de VSC nous voyons ainsi les requêtes et les éventuelles erreurs. C'est un très bon moyen de visualiser les requêtes vers le serveur. Par exemple lorsque vous avez ouvert le navigateur à l'adresse 127.0.0.1:5000/ vous avez eu une ligne qui est apparu dans la console :
127.0.0.1 - - [04/May/2020 14:55:09] "GET / HTTP/1.1" 200 -
Nous voyons ainsi l'adresse du client (ici 127.0.0.1) qui effectue une requête HTTP ( version 1.1) de type GET. Le code 200 signifie le succès de la requête .
Si dans le navigateur vous entrez l'adresse 127.0.0.1:5000/accueil vous aurez sur votre navigateur un message d'erreur. Sur la console, vous verrez le message suivant :
127.0.0.1 - - [04/May/2020 14:59:27] "GET /accueil HTTP/1.1" 404 -
Nous voyons ainsi l'adresse du client (ici 127.0.0.1) qui effectue une requête HTTP ( version 1.1) de type GET. Mais cette fois le code 404 signifie la page demandée n'est pas trouvée . LA fameuse erreur 404 du WEB 😁
Notre objectif va être de réaliser une page "contact". Pour cela la route à utiliser sera 127.0.0.1:5000/contact. Ainsi le décorateur devient :
@app.route('/contact')
Ensuite, il faut créer une nouvelle fonction qui renvoie des informations sur le webmaster (ou webmestre 🥖) , voici un exemple (à modifier !) de code :
def presentation():
message = "<h1> Présentation du webmaster </h1>"
message += "<h2> Mikael LE MENTEC </h2>"
message += "<p> Professeur de <strong>mathématiques</strong> et de <strong>NSI</strong> </p>"
message += """<a href="mailto:lesmathsduyeti@orange.fr"> Mail </a> """
return message
Ce qui donne au final le code ci-dessous pour le fichier views.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Salut le monde !"
@app.route('/contact')
def presentation():
message = "<h1> Présentation du webmaster </h1>"
message += "<h2> Mikael LE MENTEC </h2>"
message += "<p> Professeur de <strong>mathématiques</strong> et de <strong>NSI</strong> </p>"
message += """<a href="mailto:lesmathsduyeti@orange.fr"> Mail </a> """
return message
if __name__ == '__main__':
app.run(debug=True)
Enregistrez vos modifications. Le serveur étant en mode "DEBUG", il va redémarrer pour mettre à jour les fichiers qu'il va distribuer au client.
Testez-le en appelant la page 127.0.0.1:5000/contact
depuis votre navigateur internet. Vous pouvez forcer l'actualisation des pages si nécessaire.
La page devra être accessible depuis l'adresse http://127.0.0.1/loisir
@app.route('/loisir')
def loisir():
message = "<h1> Présentation de la course à pied </h1>"
message += "<h2> Pourquoi la course à pied </h2>"
message += "<p> La nature, l'exercice physique sont des plaisirs à savourer ! </p>"
return message
Pour l'instant tout fonctionne mais il y a encore des choses que l'on peut améliorer :
Pour cette dernière remarque, nous allons parler des templates ou gabarits. Mais avant, un peu de théorie sur le modèle MVC.
Nous parlons souvent de l’architecture MVC (ce n'est pas uniquement lié à Flask). Il s’agit d’un modèle distinguant plusieurs rôles précis d’une application, qui doivent être accomplis. Comme son nom l’indique, l’architecture (ou « patron ») Modèle-Vue-Contrôleur est composée de trois entités distinctes, chacune ayant son propre rôle à remplir. Voici un schéma qui résume cela :
Le MVC permet de bien organiser son code source. Il va vous aider à savoir quels fichiers créer, mais surtout à définir leur rôle. Le but de MVC est justement de séparer la logique du code en trois parties que l'on retrouve dans des fichiers distincts.
Modèle : cette partie gère les données de votre site. Son rôle est d'aller récupérer les informations « brutes » dans la base de données, de les organiser et de les assembler pour qu'elles puissent ensuite être traitées par le contrôleur. On y trouve donc entre autres les requêtes aux bases de données (programme de Terminale NSI).
Vue : cette partie se concentre sur l'affichage. Elle ne fait presque aucun calcul et se contente de récupérer des variables pour savoir ce qu'elle doit afficher. On y trouve essentiellement du code HTML mais aussi quelques boucles et conditions python très simples, pour afficher par exemple une liste de messages.
Contrôleur : cette partie gère la logique du code qui prend des décisions. C'est en quelque sorte l'intermédiaire entre le modèle et la vue : le contrôleur va demander au modèle les données, les analyser, prendre des décisions et renvoyer le texte à afficher à la vue. Le contrôleur contient exclusivement du python. C'est notamment lui qui détermine si le visiteur a le droit de voir la page ou non (gestion des droits d'accès).
Template : cette partie est le modèle de la page HTML qui sera utilisée par la vue pour générer la page HTML envoyée au client. On peut la voir comme un texte à trous dans lesquels seront insérées les données calculées par le contrôleur.
Dans l'exemple ci-dessus {{titre}}
est remplacé par "Flask c'est cool" car la variable titre devait contenir cette valeur. Ainsi la vue renvoyée est calculée à l'aide de variables.
Passons à la pratique😁
Notre objectif est de créer une page d'accueil plus sympathique. Nous allons donc modifier la fonction index
templates
dans le dossier TP_flask
index.html
avec le code suivant :<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Ma page d'accueil</title>
</head>
<body>
<h1>Un site qui déchire.</h1>
<h2>Bonjour cher visiteur !</h2>
<p>Vous voici sur mon site à moi.</p>
<a href="http://127.0.0.1:5000/contact">Lien vers les contacts.</a>
</body>
</html>
from flask import Flask,render_template
Puis modifions la fonction index comme cela :@app.route('/')
def index():
return render_template("index.html")
Visualisez le résultat dans votre navigateur. Testez le lien vers les contacts.Créez un fichier contact.html
dans le dossier templates
Dans ce dossiez écrivez un code semblable à celui-ci
<h1> Présentation du webmaster </h1>
<h2> Mikael LE MENTEC </h2>
<p> Professeur de <strong>mathématiques</strong> et de <strong>NSI</strong> </p>
<a href="mailto:lesmathsduyeti@orange.fr"> Mail </a>
Dans le fichier views.py , modifiez la fonction presentation comme cela :
@app.route('/contact')
def presentation():
return render_template("contact.html")
Pour l'instant, le serveur Flask créer toujours les même pages. Mais Flask permet de générer des vues (pages HTML) en fonction de paramètres, de formulaires ...
Commençons par améliorer l'affichage de notre page d'accueil en personnalisant l'affichage de la salutation.
Modifiez la page index.html
comme cela :
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Ma page d'accueil</title>
</head>
<body>
<h1>Un site qui déchire.</h1>
<h2>Bonjour {{prenom}} {{nom}} !</h2>
<p>Vous voici sur mon site à moi.</p>
<a href="./contact">Lien vers les contacts.</a>
</body>
</html>
Remarquez le code {{prenom}} {{nom}}
. Le contrôleur remplacera ces variables par celles qui seront fournies par la fonction index
.
Modifions donc la fonction index
du fichier views.py
comme qui suit :
@app.route('/')
def index():
p = "mikaël"
n = "le mentec"
return render_template("index.html",prenom = p, nom = n)
Enregistrez et allez voir le résultat dans votre navigateur.
Pour l'instant, il faut changer à la main les variables pour que le nom affiché soit le bon, MAIS ce n'est que le début. Nous verrons plus tard comment, avec un formulaire, nous pourrons adapter la page à l'utilisateur.
Un dernier raffinement modifiez le fichier html ainsi : Bonjour {{prenom|capitalize}} {{nom|upper}} !
Le prénom et le nom seront affiché avec la bonne "casse" et cela même si les variables ne sont pas bien écrites.
Autre défaut qui me dérange, nous n'utilisons pas vraiment le potentiel d'un ordinateur, demandons des tâches plus complexes (mais pas trop , ce n'est qu'un modeste cours d'introduction ... 😉 )
Voici le fichier views.py dans le lequel deux imports sont réalisés. L'heure exacte du serveur et un calcul arithmétique sont effectués et stockés dans les variables heure, minute ...
from flask import Flask,render_template
import datetime
from math import pi
app = Flask(__name__)
@app.route('/')
def index():
p = "mikaël"
n = "le mentec"
date = datetime.datetime.now()
heure = date.hour
minute = date.minute
seconde = date.second
r = 2
aire = pi*r**2
return render_template("index.html",prenom = p, nom = n, heure = heure, minute=minute, seconde=seconde, rayon = r, aire = aire)
Dans le fichier index.html
ces variables sont affichées via les appels {{heure}} {{minute}} etc ...
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Ma page d'accueil</title>
</head>
<body>
<h1>Un site qui déchire.</h1>
<h2>Bonjour {{prenom|capitalize}} {{nom|upper}} !</h2>
<p>Vous voici sur mon site à moi.</p>
<p> Il est {{heure}} h {{minute}} m {{seconde}} s (heure du serveur !)</p>
<p> Pour info, l'aire d'un disque de rayon {{rayon}} cm est d'environ {{aire}} cm²</p>
<a href="./contact">Lien vers les contacts.</a>
</body>
</html>
Testez l'affichage dans votre navigateur.
Pour vous aider :
datetime.datetime(a,m,j)
permet de créer un objet date de l'année a, mois m et jours j.days
à la suite de l'objet dateVoici le code à ajouter à votre fichier views.py
@app.route('/contact')
def presentation():
date_naissance = datetime.datetime(1998, 7, 12)
duree = datetime.datetime.now() - date_naissance
jours = duree.days
return render_template("contact.html",naissance = date_naissance ,jours=jours)
Et volà le code à écrire dans le fichier contat.html
<h1> Présentation du webmaster </h1>
<h2> Mikael LE MENTEC </h2>
<p> Professeur de <strong>mathématiques</strong> et de <strong>NSI</strong> </p>
<p>Je suis né le {{naissance.day}}/{{naissance.month}}/{{naissance.year}} cela fait exactement {{jours}} jours</p>
<a href="mailto:lesmathsduyeti@orange.fr"> Mail </a>
Modifiez le fichier index.
html
comme ceci :
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Ma page d'accueil</title>
</head>
<body>
<h1>Un site qui déchire.</h1>
<h2>Bonjour {{prenom|capitalize}} {{nom|upper}} !</h2>
<p>Vous voici sur mon site à moi.</p>
<p> Il est {{heure}} h {{minute}} m {{seconde}} s (heure du serveur !)</p>
<p> Pour info, l'aire d'un disque de rayon {{rayon}} cm est d'environ {{aire}} cm²</p>
<form action="http://127.0.0.1:5000/resultat" method="get">
<label>Nom</label> : <input type="text" name="nom" />
<label>Prénom</label> : <input type="text" name="prenom" />
<input type="submit" value="Envoyer" />
</form>
</body>
<footer><a href="127.0.0.1/contact">Lien vers les contacts.</a></footer>
</html>
Affichez la page d'accueil et complétez le formulaire qui est apparu. Quand vous cliquez sur le bouton Envoyer, que se passe-t-il ? 🤔
Un message d'erreur, mais en même temps c'est logique !
<form action="http://127.0.0.1:5000/resultat" method="get">
Ce code signifie que l'envoi du formulaire se fait avec la méthode GET et que la page affichée ensuite sera celle de l'adresse 127.0.0.1/resultat. Or pour l'instant, cette adresse n'est pas répertoriée dans nos fichiers. Il n'y a pas de route associée.
Autre remarque, observez bien l'adresse obtenue http://localhost:5000/resultat?nom=LE+MENTEC&prenom=Mikael
Comme vous pouvez le constater, les données envoyées apparaissent dans l'adresse. C'est la méthode GET qui veut cela.
Avec cette méthode, les données du formulaire seront encodées dans une URL. Celle-ci est composée du nom de la page ou du script à charger avec les données de formulaire empaquetée dans une chaîne. Les données sont séparées de l'adresse de la page pas le code ? et entre elles par le code & .
Pas très sécurisé comme méthode, le fait de voir les données dans l'adresse a plusieurs inconvénient :
Modifions le fichier views.py
comme ceci :
Ajoutez l'import suivant :
from flask import Flask,render_template,request
Et ensuite ajoutez la fonction suivante :
@app.route('/resultat',methods = ['GET','POST'])
def salutation():
if request.method == 'GET':
return request.args
else: # request.methode != 'GET'
return "post"
Cette fonction sera appelée lors de l'envoi du formulaire.
if request.method == 'GET':
permet de choisir une action si la page est obtenue via une requête de type GETrequest.args
va s'afficher, vous pouvez constater que c'est un objet de type dictionnaire. Pour accéder au nom il va falloir utiliser la syntaxe des dictionnaires : request.args['nom']
Créer un fichier resultat.html
dans le dossier templates
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Salutations !</title>
</head>
<body>
<p>Bonjour, en fait vous vous nommez {{prenom}} {{nom}} !</p>
</body>
</html>
Notez que nous avons besoin des variables prenom
et nom
. Nous allons les récupérer dans notre dictionnaire request.args
Modifiez le fichier views.py
comme ceci :
@app.route('/resultat',methods = ['GET','POST'])
def salutation():
if request.method == 'GET':
prenom_visiteur = request.args['prenom']
nom_visiteur = request.args['nom']
return render_template('resultat.html',prenom=prenom_visiteur,nom=nom_visiteur)
elif request.method == 'POST':
return "post"
Testez l'envoi d'un formulaire. Maintenant vous devriez avoir un message correct.
Voyons l'autre méthode possible pour envoyer un formulaire. Modifiez la méthode d'envoi du formulaire (dans le fichier index.html
)ainsi :
<form action="http://127.0.0.1:5000/resultat" method="post">
Si vous cliquez sur le bouton du formulaire, pas d'erreur, vous devriez voir écrit "post" sur votre page web. (rechargez la page html si cela ne se produit pas)
Notez aussi que les valeurs entrées dans le formulaire ne sont plus transmisent par l'URL. Mais elle sont quand même transmisent ! 😅
Pour les voir, modifiez le fichier views.py comme cela :
@app.route('/resultat',methods = ['GET','POST'])
def salutation():
if request.method == 'GET':
prenom_visiteur = request.args['prenom']
nom_visiteur = request.args['nom']
return render_template('resultat.html',prenom=prenom_visiteur,nom=nom_visiteur)
elif request.method == 'POST':
return request.form
Vous devriez reconnaître un dictionnaire qui ressemble furieusement au dictionnaire de la méthode GET.
Nous touchons au but, modifiez le fichier views.py comme ceci :
@app.route('/resultat',methods = ['GET','POST'])
def salutation():
if request.method == 'GET':
prenom_visiteur = request.args['prenom']
nom_visiteur = request.args['nom']
elif request.method == 'POST':
prenom_visiteur = request.form['prenom']
nom_visiteur = request.form['nom']
return render_template('resultat.html',prenom=prenom_visiteur,nom=nom_visiteur)
Testez ce code, notez bien la différence entre les méthodes GET et POST pour récupérer les données. L'usage qui en est fait par contre lui reste inchangé.
La méthode POST est indispensable pour
Vous trouverez ci-dessous les fichiers de ce TP au cas où vous avez perdu le fil.
Fichiers du TPVisitez ce site pour comprendre le codage de césar
Pour réaliser cet exercice, il faut :
Je vous donne le code de la fonction cesar
def cesar(texte, cle):
"""
Fonction de codage par décalage (césar)
Entrées : une chaine de caractères et un entier
Sortie : une chaine de caractère
"""
texte_code = ""
for char in texte:
if char.isalpha(): #si le caractère est une lettre on décale
nouvelIndice = ord(char) + cle
#Pour rester dans l'aplphabet, on décale de 26 en arrière si besoin
if ord(char) <= ord('z') < nouvelIndice or ord(char) <= ord('Z') < nouvelIndice:
nouvelIndice -= 26
lettrefinale = chr(nouvelIndice)
texte_code += lettrefinale
else: #si le caractère n'est pas une lettre, on n'y touche pas
texte_code += char
return texte_code
Voici le fichier contenant la réponse.