TP FLASK⚓︎
Interactions client - serveur (FLASK)⚓︎
Objectif : visualiser des interactions entre le client et le seveur (qui seront ici une seule et même machine)
1. Le modèle client serveur⚓︎
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 😉
2. Démarrage du serveur⚓︎
-
Créez un dossier nommé TP_Flask
-
Ouvrez Pyzo et créer un fichier nommé
views.py
(il sera placé dans le répertoire TP_Flask ) -
Saisissez le code suivant :
Python | |
---|---|
- Exécutez alors le fichier. Patientez. Si cela fonctionne, vous devriez avoir le résultat suivant qui apparaît dans la console :
Le code signifie que le serveur est bien lancé à l’adresse IP 127.0.0.1 et sur le port 5000. Pour visualiser le résultat nous allons utiliser un navigateur internet.
-
Ouvrez votre navigateur internet et dans la barre d’adresse entrez : 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.
3. Analyse et un peu de théorie⚓︎
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 :
Permet d’importer le module flask Créer un objet app : cette ligne est systématique nécessaire. 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") 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. 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 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 : 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 :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 😁
Une nouvelle page 🤩⚓︎
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 :
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> Le Professeur </h2>"
message += "<p> Enseignant de <strong>physique-chimie</strong> et de <strong>NSI</strong> </p>"
message += """<a href="mailto:physique-chimie@orange.fr"> Mail </a> """
return message
views.py
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.
Exercice 1
En vous inspirant de l'exemple précédent, créez une page décrivant votre activité préférée 😉
La page devra être accessible depuis l'adresse http://127.0.0.1/loisir
4. Le modèle MVC.⚓︎
Pour l'instant tout fonctionne mais il y a encore des choses que l'on peut améliorer :
- il n'y a pas d'interaction avec l'utilisateur, nous verrons cela avec les paramètres des fonctions et les formulaires
- et taper du code html dans un fonction python, ce n'est pas trop propre ! 😇
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 :
MVC
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.
5. Un exemple de template⚓︎
Notre objectif est de créer une page d'accueil plus sympathique. Nous allons donc modifier la fonction index
-
Créer un dossier
templates
dans le dossierTP_flask
-
Dans ce dossier, créer un fichier
index.html
à l'aide de Notepad++ 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>
- Nous voulons maintenant afficher cette page lors de l'accès à l'adresse
127.0.0.1/
Il faut dans un premier temps importer un nouvel objet, modifiez la première ligne du fichierviews.py
comme ceci :
- Puis modifions la fonction
index
comme cela :
- Visualisez le résultat dans votre navigateur. Testez le lien vers les contacts.
Exercice 2
Modifiez la fonction qui permet l'affichage du contact 📇 pour qu'elle utilise un template.
Créez un fichier 'contact.html' dans le dossier 'templates'
Dans ce fichier écrivez un code semblable à celui-ci
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Ma page contact</title>
</head>
<body>
<h1> Présentation du webmaster </h1>
<h2> Le Professeur </h2>
<p> Enseignant de <strong>physique-chimie</strong> et de <strong>NSI</strong> </p>
<a href="mailto:physique-chimie@orange.fr"> Mail </a>
</body>
</html>
views.py
, modifiez la fonction presentation comme cela :
Exercice 3
Modifiez la fonction qui permet l'affichage du loisir pour qu'elle utilise un template.
6. Dynamiser les pages⚓︎
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>
Remarque
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 = "Le"
n = "Professeur"
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 index.html
ainsi : Bonjour {{ prenom }}
{{ NOM }}
!
- Le prénom et le nom seront affiché avec la bonne "casse" et cela même si les variables ne sont pas bien écrites.
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 ...
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 }} {{ NOM }} !</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>
Exercice 4
Modifiez la fonction contact et le template associé pour : - Calculer le nombre de jours depuis votre date de naissance - Afficher une phrase du genre : "Je suis né le xx/xx/xxxx cela fait xxxx jours"
Pour vous aider :
-
importez le module
datetime
de python -
datetime.datetime(a,m,j)
permet de créer un objet date de l'année a, mois m et jours j- Exemple 1 : 'date_naissance datetime.datetime(1998, 7, 12)'
-
datetime.datetime.now()
permet de créer un objet avec la date d'aujourd'hui -
Pour récupérer le nombre de jour d'un objet date, if faut ajouter '.days' à la suite de l'objet date
Voici 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 voilà le code à écrire dans le fichier contact.html
7. Utilisation d'un formulaire (méthode GET)⚓︎
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 }} {{ NOM }} !</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 !
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&prenom=Professeur
. Comme vous pouvez le constater, les données envoyées apparaissent dans l'adresse. C'est la méthode GET qui veut cela.
Modifions le fichier views.py
comme ceci :
Ajoutez l'import suivant :
@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>
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"
8. Utilisation d'un formulaire (méthode POST)⚓︎
Voyons l'autre méthode possible pour envoyer un formulaire. Modifiez la méthode d'envoi du formulaire (dans le fichier index.html
)ainsi :
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é.