Vous êtes sur la page 1sur 64

Web Services avec Flask : Applications Web et API

1. Les objectifs de l’EC:


A la fin de l’EC, l’apprenant devrait être capable de :
1.1 Concevoir et développer une API REST avec Python
1.2 Créer des interfaces d’utilisation d’une API
1.3 Sécuriser l’accès à l’API
1.4 Générer le paquetage d’installation d’une API
1.5 Déployer une API en utilisant WSGI avec les serveurs web du marché (apache2, nginx, etc.)
2. Les Prérequis :
• Pour atteindre les objectifs l’apprenant doit avoir une connaissance de HTML, CSS, et de
Python.
• Une connaissance de base en JavaScript et en requêtes SQL peut faciliter la compréhension
de cet EC.
• Une connaissance de base en hébergement et en activation de modules Apache est un atout
pour mieux aborder cet EC.
Notamment les prérequis nécessaires : les formulaires, les tableaux, les feuilles de style,
2. Séquences de l’EC:
3.1 Séquence 1 : Environnement de développement
3.2 Séquence 2 : Structure d’une application flask et paramètres de Flask, route(), run().
3.3 Séquence 3 : Construction d’url et notion de template(url_for, redirect render_template)
3.4 Séquence 4 : verbes HTTP : GET, PUT, POST, DELETE, HEAD : request.form,
request.args.get (import du module request)
3.5 Séquence 5 : Inclusion du code Python dans les templates (pages html) : instructions
conditionnelles et boucles
3.6 Séquence 6 : La notion de Static : Code Javascript (notion de dossier et fichier.js, feuilles de
style CSS
3.7 Séquence 7 : Les Objets de requêtes : Formulaire, args, fichier, cookies, methodes
3.8 Séquence 8 : Utilisation d’importation de modules python de base de données dans Flask
3.9 Séquence 9 : Extensions flask : Mail, WTF, Sqlite, SQLAlchemy
3.10 Séquence 10 : Gestion de Multimédia : photo, vidéo, audio
3.11 Séquence 11: Paquetage et déploiement
3.12 Séquence 12: Étude du module RESTFul de flask
3.13 Séquence 13 : Sécurité API : authentification
3.14 Séquence 14 : Synthèse sur les interfaces d’utilisation d’API
Introduction
Flask est un framework open-source de développement web en Python. Son but principal est d'être
léger, afin de garder la souplesse de la programmation Python, associé à un système de templates. Il
est distribué sous licence BSD.
Il dispose de plusieurs modules permettant de développer de fonctionnalités particulières selon les
besoins. C’est le cas du module RESTful qui nous permet de développer des API REST.
Flask intègre aussi les modules de gestion de connexion à une base de données et
d’authentification.
Comme tout langage de programmation, on doit pouvoir comprendre :
• les entrées sorties ;
• les types de variables ;
• les instructions conditionnelles ;
• les boucles ;
• les sous programmes
I. Séquence 1 : Environnement de développement
L’objectif pédagogique de cette séquence est de pouvoir installer et utiliser un environnement
virtuel de développement afin de régler les conflits éventuels de modules python.
Ainsi on peut avoir une version python système d’exploitation différente de la version de
développement à travers l’environnement virtuel.

I.1. Installer virtualenv pour l'environnement de développement


virtualenv est un constructeur d'environnement Python virtuel. Cela aide un utilisateur à créer
plusieurs environnements Python côte à côte. Ainsi, cela peut éviter des problèmes de compatibilité
entre les différentes versions de Python.
La commande suivante installe virtualenv

pip install virtualenv

Cette commande nécessite des privilèges d'administrateur. Ajoutez sudo avant pip sous Linux /
Mac OS. Si vous êtes sous Windows, connectez-vous en tant qu'administrateur. Sur Ubuntu,
virtualenv peut être installé à l'aide de son gestionnaire de paquets.

Sudo apt-get install virtualenv

Une fois installé, le nouvel environnement virtuel est créé dans un dossier.

mkdir newproj
cd newproj
virtualenv venv
source venv/bin/activate
Nous sommes maintenant prêts à installer Flask dans cet environnement.

pip install Flask

1. Donner la définition de flask


2. Quel est l’intérêt de les environnements virtuels ?
3. Quels sont les différentes étapes pour créer un environnement virtuel .
4. Comment activer un environnement virtuel ?
5. Comment désactiver un environnement virtuel ?
II. Séquence 2 : Structure d’une application flask et paramètres de Flask, route(), run().
Pour mieux démarrer le développement d’applications avec flask il est important de comprendre la
structure générale d’un programme flask :
• importation de modules ;
• définition de l’application et de commentaire ;
• définition de routes qui constituent les urls et les fonctions à appeler quand on accède à ces
urls;
• programme principal et définition de socket d’écoute
II.1 Premier programme en Flask
Afin de tester l’ installation de Flask , tapez le code suivant dans l’éditeur sous le nom Hello.py

from flask import Flask # importation de module Flask


app = Flask(__name__) # Définition de l’application

@app.route('/') # Définition de routes


def hello_world():
return 'Hello World’
if __name__ == '__main__': # Définition du programme pricipal
app.run()

On peut exécuter le programme par la commande suivante comme le montre la figure ci-dessous :
# python hello.py

Le serveur web cré dans flask démarre sur l’adresse 127.0.0.1 et le port 5000.

Test d’un programme flask avec la commande curl


On ouvre un autre terminal et on exécute la commande suivante : curl http://127.0.0.1:5000

On peut aussi tester le programme dans un navigateur comme suit :


II.2. La structure d’un programme en flask

L'importation du module flask est obligatoire dans un programme flask :


from flask import Flask

Le constructeur de flask prend comme argument le nom du module (__name_₎ :


app = Flask(__name__)

La fonction route() de la classe Flask est un décorateur, qui indique à l'application quelle URL doit
appeler la fonction associée.

app.route(rule, options)

• Le paramètre de règle représente la liaison d'URL avec la fonction.

• Les options sont une liste de paramètres à transmettre à l'objet de règle sous-jacent.

Dans l'exemple ci-dessus, l' URL '/' est liée à la fonction hello_world () . Par conséquent, lorsque
la page d'accueil du serveur Web est ouverte dans un navigateur, le résultat de cette fonction sera
rendu ou affiché.

Enfin, la méthode run () de la classe Flask exécute l'application sur le serveur de développement
local.

app.run(host, port, debug, options)

Numéro Paramètre de description


1 hôte
Nom d'hôte pour écouter. La valeur par défaut est 127.0.0.1 (localhost).
Défini sur '0.0.0.0' pour que le serveur soit disponible en externe

2 Port
La valeur par défaut est 5000

3 déboguer
La valeur par défaut est false. Si défini sur true, fournit des informations de
débogage

4 Les options
À transmettre au serveur Werkzeug sous-jacent.

II.3. Mode débogage


Une application Flask est démarrée en appelant la méthode run () . Cependant, pendant le
développement de l'application, vous devez la redémarrer manuellement à chaque modification du
code. Pour éviter ce désagrément, activez le support de débogage . Le serveur se rechargera
ensuite si le code change. Il fournira également un débogueur utile pour suivre les erreurs
éventuelles dans l'application.
Le mode débogage est activé en définissant la propriété debug de l' objet d' application sur True
avant d'exécuter ou de transmettre le paramètre debug à la méthode run () .

app.debug = True
app.run()
ou
app.run(debug = True)

II.4. Accès directe à une page sans passer forcément par la page d’accueil
Deux méthodes à cet effet

Principe de route :

On peut utiliser le décorateur route () dans Flask pour lier une URL à une fonction.
On peut le faire de deux manières comme suit :

Méthode 1

@app.route(‘/hello’)
def hello_world():
return ‘hello world’

Ici, la règle URL '/ hello' est liée à la fonction hello_world () . Par conséquent, si un utilisateur
visite http: // localhost: 5000 / hello URL, la sortie de la fonction hello_world () sera restituée
dans le navigateur.

Méthode 2
La fonction add_url_rule () d'un objet d'application est également disponible pour lier une URL
avec une fonction, comme dans l'exemple ci-dessus, route () est utilisé.
Le but d'un décorateur est également servi par la représentation suivante -
def hello_world():
return ‘hello world’
app.add_url_rule(‘/’, ‘hello’, hello_world)

II.4. Notion de paramètre dans un Décorateur de type route()


Dans certaine situation on a besoin de passer des paramètres à une fonction.

On voudrait si un utilisateur saisit http://127.0.0.1:5000/hello/SonNom alors on affiche hello


SonNom.

Dans capture qui suit SonNom a été remplacé par Samuel

Voici le code en flask :

from flask import Flask


app = Flask(__name__)
@app.route('/hello/<name>')
def hello_name(name):
return 'Hello %s!' % name
if __name__ == '__main__':
app.run(debug = True)

On a testé le programme dans un navigateur en remplaçant SonNom par Aly et on obtient :

II.5. Quelques types de paramètres supportés par le décorateur route()

Numéro Paramètre de description


1 int : accepte les entiers
2 float : accepte les réels
3 string : accepte les chaînes de caractères
4 path : accepte les chemins de fichiers
On crée un fichier typeflask.py comme suit :

from flask import Flask


app = Flask(__name__)

@app.route('/moyenne/<int:note>')
def affiche_moyenne(note):
return 'Votre note est de : %d' % note

@app.route('/solde/<float:montant>')
def montre_solde(montant):
return 'Le montant de votre solde est de : %f' % montant

@app.route('/chaine/<string:nomcomplet>')
def affiche_chaine(nomcomplet):
return ' %s, nous vous souhaitons bonne journee' % nomcomplet

if __name__ == '__main__':
app.run()

II.5.1 Test du type entier (int)

Test du type réel (float)

Si on appelle le programme avec un paramètre de type chaîne de caractère on obtient une erreur
comme le montre la figure ci-après :
Test du type de chaîne de caractère (float)

NB : il faut remarquer les formats %d, %f, %s utilisés dans les réponses et % NomParamètre
qui permet de récupérer le contenu du paramètre.

NB : On peut dire que les routes désignent les pages à afficher.

Quelques questions à répondre

1. Quelle est la structure générale d’un programme flask ?


2. Donner la définition de route dans le contexte flask
3. Quels sont les principaux paramètres du décorateur route() ?
4. Quels sont les principaux paramètres de classe run() ?
5. Quels sont les formats des types de variable suivants :
• int
• float
• string
III. Séquence 3 : Construction d’url et notion de template(url_for, redirect render_template)
Trois notions importantes seront abordées dans cette séquence :
• la fonctionredirect(http://IP ou url) qui permet de rediriger vers une url ;
• la fonction url_for qui permet de faire appel à une fonction spécifique d’un programme
flask à l’intérieur du dit programme
III.1. Construction d’URL
La fonction url_for () est très utile pour construire dynamiquement une URL pour une fonction
spécifique. La fonction accepte le nom d'une fonction en tant que premier argument et un ou
plusieurs arguments de mots clés, chacun correspondant à la partie variable de l'URL. Le script
suivant illustre l'utilisation de la fonction url_for () .

from flask import Flask, redirect, url_for


app = Flask(__name__)

@app.route('/admin')
def hello_admin():
return 'Bonjour patron Admin'

@app.route('/guest/<invite>')
def hello_guest(invite):
return 'Bonjour %s comme Invite' % invite

@app.route('/user/<name>')
def hello_user(name):
if name =='admin':
return redirect(url_for('hello_admin'))
else:
return redirect(url_for('hello_guest',invite = name))

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

Remarquez qu’on a importé deux fonctions supplémentaires redirect, url_for

On teste la première fonction qui a pour url /admin on obtient la page suivante :

Si on teste avec un autre nom différent de admin on obtient la page suivante :


NB : remarquer bien la syntaxe des instructions if et else

Quelques questions à répondre

1. Quelle est la fonction de flask à importer pour appeler une route avec des parametres
2. Quelle est la fonction de flask à importer pour rediriger vers une autre page web ?
IV. Séquence 4 et 5 : verbes HTTP : GET, PUT, POST, DELETE, HEAD : request.form,
request.args.get (import du module request), Template, instructions conditionnelles et boucles
L’objectif de cette séquence est vous montrer comment utiliser les verbes HTTP, utiliser les
templates et leurs faire passer des paramètres selon des critères.
Nous aborderons aussi dans cette séquence le passage de paramètres à un template, l’utilisation des
instructions conditionnelles et boucles python dans un template pour rendre dynamique certaines
actions.
IV.1. les Méthodes HTTP
Le protocole HTTP est la base de la communication de données sur le World Wide Web. Différentes
méthodes de récupération de données à partir d'une URL spécifiée sont définies dans ce protocole.
Le tableau suivant récapitule différentes méthodes http -

Numéro Paramètres de description


1 GET : Envoie des données sous forme non chiffrée au serveur. Méthode
la plus commune.
2 HEAD : Identique à GET, mais sans corps de réponse
3 POST Utilisé pour envoyer des données de formulaire HTML au serveur.
Les données reçues par la méthode POST ne sont pas mises en cache par
le serveur.
4 PUT : Remplace toutes les représentations actuelles de la ressource cible
par le contenu téléchargé.
5 DELETE :Supprime toutes les représentations actuelles de la ressource
cible donnée par une URL

Par défaut, la route Flask répond aux demandes GET . Cependant, cette préférence peut être
modifiée en fournissant un argument de méthodes au décorateur route ().
Afin de démontrer l'utilisation de la méthode POST dans le routage d'URL, créons d'abord un
formulaire HTML et utilisons la méthode POST pour envoyer des données de formulaire à une
URL.
Enregistrez le script suivant sous le nom formulaire.html
<html>
<body>
<form action = "http://localhost:5000/login" method = "post">
<p>Enter votre Nom:</p>
<p><input type = "text" name = "nom" /></p>
<p><input type = "submit" value = "valider" /></p>
</form>
</body>
</html>
Créons le programme flask login.py :
from flask import Flask, redirect, url_for, request
app = Flask(__name__)
@app.route('/success/<name>')
def success(name):
return ' Bienvenue %s ' % name
@app.route('/login',methods = ['POST', 'GET'])
def login():
if request.method == 'POST':
user = request.form['nom']
return redirect(url_for('success',name = user))
else:
user = request.args.get('nom')
return redirect(url_for('success',name = user))
if __name__ == '__main__':
app.run(debug = True)
On lance le programme login.py comme suit :

On ouvre le formulaire dans un navigateur comme suit :

Donner votre Nom et cliquer sur valider :


On obtient la page suivante :

Pour tester la méthode GET on utilise directement un navigateur tout en précisant le paramètre :

IV.2. La notion de Template ou modèle en français

Il est possible de renvoyer la sortie d'une fonction liée à une certaine URL sous la forme HTML. Par
exemple, dans le script suivant, la fonction hello () affichera "Hello World" avec la balise <h1>
qui y est associée.

Cependant, générer du contenu HTML à partir de code Python est fastidieux, en particulier lorsque
des données variables et des éléments du langage Python tels que des conditions ou des boucles
doivent être insérés. Cela nécessiterait de fréquents échappements de HTML.

C’est là que l’on peut tirer parti du moteur de gabarit Jinja2 , sur lequel repose Flask. Au lieu de
renvoyer du code HTML à partir de la fonction, un fichier HTML peut être rendu par la fonction
render_template () .

Créer dans le dossier du projet le fichier sanstemplate.py comme suit :

from flask import Flask


app = Flask(__name__)

@app.route('/')
def index():
return '<html><body><h1>Bonjour tout le monde</h1></body></html>'

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

On lance le programme sanstample.py et on utilise un navigateur pour le tester comme suit :


On se rencontre qu’une fonction flask peut exécuter du code HTML

Introduction des templates pour faciliter les choses

Pour cela créons un sous dossier nommé templates dans le dossier du projet avec la commande :

Allons dans le sous dossier templates et créons le fichier templates hello.html comme suit :

<!doctype html>
<html>
<body>

<h1>Bonjour {{ name }}!</h1>

</body>
</html>

On crée dans le dossier du projet le programme avectemplate.py comme suit :

flask import Flask, render_template


app = Flask(__name__)

@app.route('/hello/<user>')
def hello_name(user):
return render_template('hello.html', name = user)

if __name__ == '__main__':
app.run(debug = True)
Noter que le template hello.html reçoit le paramètre name et noter bien comment on l’a écrit dans le
template {{ name }}.

Le moteur de modèle Jinga2 utilise les délimiteurs suivants pour échapper à HTML.
• {% ...%} pour les déclarations

• {{...}} pour les expressions à imprimer sur la sortie du modèle

• {# ... #} pour les commentaires non inclus dans la sortie du modèle

• # ... ## pour les instructions de ligne

Dans l'exemple suivant, l'utilisation de l'instruction conditionnelle dans le modèle est démontrée. La
règle d'URL de la fonction hello() accepte le paramètre entier. Il est transmis au modèle
helloDevoir.html .
À l'intérieur, la valeur du nombre reçu (marques) est comparée (supérieure ou inférieure à 50) et, en
conséquence, le code HTML est restitué sous forme conditionnelle.
Le script Python templatecondition.py est comme suit -
from flask import Flask, render_template
app = Flask(__name__)

@app.route('/hello/<int:note>')
def hello_name(note):
return render_template('helloDevoir.html', devoir = note)

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

Le contenu du fichier templates templates/helloDevoir.html comme suit :


<!doctype html>
<html>
<body>
{% if devoir>12 %}
<h1> Vous passez en classe superieure !</h1>
{% else %}
<h1>Votre resultat n est pas bon </h1>
{% endif %}
</body>
</html>

On exécute le code python en donnant la note 13 comme suit :


On exécute la code python en donnant la note 8 comme suit :

IV.3. Boucle Python dans un template


L’exemple suivant montre l’utilisation d’un boucle dans un template flask
Voici le code du programme boucle.py :
from flask import Flask, render_template
app = Flask(__name__)

@app.route('/result')
def result():
dict = {'programmation':18,'reseau':17,'maths': 9,'telecoms':16}
return render_template('boucle.html', result = dict)
if __name__ == '__main__':
app.run(debug = True)

Voici le code du fichier template templates/boucle.html :


<!doctype html>
<html>
<body>
<table border = 1>
{% for key, value in result.iteritems() %}
<tr>
<th> {{ key }} </th>
<td> {{ value }} </td>
</tr>
{% endfor %}
</table>
</body>
</html>
On lance le programme boucle.py et on teste dans un navigateur et on obtient :

Remarque :
Non seulement on a introduit la notion de boucle dans un template et on introduit aussi la notion de
tableau dans html.

Quelques questions à répondre

1. Que signifie template dans le contexte de flask ?


2. Que représente jinja2 dans le contexte flask ?
3. Comment les paramètres sont integrés dans un fichier template ?
4. Quels sont les types de paramètres qu’on peut transmettre à un fichier template ?
5. Quel est le nom de la fonction à importer dans flask pour recuperer des donn ées par la
6. methode GET ou POST ?
7. Quel est le rôle de la fonction render_template ?
V. Séquence 6 : La notion de Static : Code Javascript (notion de dossier et fichier.js, feuilles de
style CSS
Cette séquence permet d’aborder l’une des notions les plus importantes utilisées pour la structure
d’un dossier de projet flask :
• notion de dossier static dans lequel on met le sous dossier css contenant les feuilles de style
et le sous dossier script dans lequel on met les éventuels scripts Javascript d’un projet
V.1. Les fichiers statiques
Une application Web nécessite souvent un fichier statique tel qu'un fichier javascript ou un fichier
CSS prenant en charge l'affichage d'une page Web. Généralement, le serveur Web est configuré
pour les servir, mais pendant le développement, ces fichiers sont servis à partir du dossier statique
de votre package. Ils seront disponibles dans le sous dossier static de votre projet.
Dans l'exemple suivant, une fonction javascript définie dans hello.js est appelée dans l' événement
OnClick du bouton HTML dans index.html , qui est restitué dans l' URL '/' de l'application Flask.
Pour cela créons le sous dossier static dans notre dossier projet :

a. On édite le fichier static.py comme suit :

from flask import Flask, render_template


app = Flask(__name__)

@app.route("/")
def index():
return render_template("static.html")

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

b. Créons le fichier templates/static.html

<html>
<head>
<script type = "text/javascript"
src = "{{ url_for('static', filename = 'hello.js') }}"
></script>
</head>
<body>
<input type = "button" onclick = "sayHello()" value = "Say
Hello" />
</body>
</html>
NB : Comment faire appel à un script dans un template en précisant le dossier contenant le code
Javascript et nom du fichier : src = "{{ url_for('static', filename =
'hello.js') }}"
c. On crée le fichier javascript static/hello.js comme suit :
function sayHello() {
alert("Bonjour tout le monde")
}
On exécute le programme static.py et on le teste à travers un navigateur ; on obtient :

En cliquant sur Dit Bonjour le code Javascript est exécuté comme suit :

Exemple d’envoi de formulaire à un programme flask


Principe :
a. On crée le formulaire en lui précisant dans l’action une route() vers lequel envoyer le formulaire
b. On crée une route () d’appel d’un formulaire
c. Dans la route d’envoi de formulaire on appelle un template de traitement de formulaire
Application :
a. On crée le fichier templates/etudiant.html contenant notre formulaire comme suit :
<html>
<body>
<form action = "http://localhost:5000/result" method = "POST">
<p>Name <input type = "text" name = "Name" /></p>
<p>Programmation <input type = "text" name = "prog" /></p>
<p>Reseau <input type = "text" name = "reseau" /></p>
<p>Maths <input type ="text" name = "math" /></p>
<p><input type = "submit" value = "valider" /></p>
</form>
</body>
</html>

b. On crée le fichier form.py comme suit :

from flask import Flask, render_template, request


app = Flask(__name__)
@app.route('/')
def student():
return render_template('etudiant.html')
@app.route('/result',methods = ['POST', 'GET'])
def result():
if request.method == 'POST':
result = request.form
return render_template("result.html",result = result)
if __name__ == '__main__':
app.run(debug = True)

On crée le fichier templates/result.html de traitement du formulaire comme suit :

<!doctype html>
<html>
<body>
<table border = 1>
{% for key, value in result.items() %}
<tr>
<th> {{ key }} </th>
<td> {{ value }} </td>
</tr>
{% endfor %}
</table>
</body>
</html>

On exécute le programme form.py et on le teste à travers un navigateur et on obtient :


Après remplissage des champs et validation on obtient :

Quelques questions à répondre

1. Donner les étapes à suivre pour envoyer un formulaire html à un programme dans flask
2. Quelles sont les différentes étapes pour intégrer du code JavaScript ou des feuilles de style
dans un template ?
3. Quel est le module importé pour pouvoir récupérer les données du formulaire ?
4. Expliquer les arguments donnés à la fonction render_temple dans le programme flask
VI. Séquence 7 : Les Objets de requêtes : Formulaire, args, fichier, cookies, methodes
V.2. Objet de requête
Les données de la page Web d'un client sont envoyées au serveur en tant qu'objet de requête global.
Afin de traiter les données de la demande, celles-ci doivent être importées du module Flask.
Les attributs importants de l'objet de requête sont listés ci-dessous -
• Formulaire - Il s'agit d'un objet dictionnaire contenant des paires clé / valeur de paramètres
de formulaire et leurs valeurs.
• args - contenu analysé de la chaîne de requête qui fait partie de l'URL après le point
d'interrogation (?).
• Cookies - objet dictionnaire contenant les noms et les valeurs des cookies.

• fichiers - données relatives au fichier téléchargé.

• méthode - méthode de demande en cours.


On aborde dans cette séquence comment parcourir sa machine en vu d’envoyer un fichier et le
sauvegarder dans un dossier spécifié.
Deux notions importantes sont aussi abordées à savoir les cookies et les sessions
VI.1 Objectifs pédagogiques : Envoi de fichier

La gestion du téléchargement de fichiers dans Flask est très simple. Il a besoin d'un formulaire
HTML avec son attribut enctype défini sur 'multipart / form-data', en publiant le fichier dans une
URL. Le gestionnaire d'URL extrait le fichier de l'objet request.files [ ] et l'enregistre à
l'emplacement souhaité.
Chaque fichier téléchargé est d'abord enregistré dans un emplacement temporaire sur le serveur,
avant d'être enregistré dans son emplacement ultime. Le nom du fichier de destination peut être
codé en dur ou peut être obtenu à partir de la propriété filename de l'objet request.files [fichier] .
Toutefois, il est recommandé d’en obtenir une version sécurisée à l’aide de la fonction
secure_filename () .
Il est possible de définir le chemin du dossier de téléchargement par défaut et la taille maximale du
fichier téléchargé dans les paramètres de configuration de l'objet Flask.

app.config ['UPLOAD_FOLDER'] Définit le chemin du dossier de téléchargement


app.config ['MAX_CONTENT_PATH'] Spécifie la taille maximale du fichier à
télécharger - en octets

Le code suivant contient la règle d'URL '/upload' qui affiche 'upload.html' à partir du dossier des
modèles et la règle d'URL '/upload-file' qui appelle le processus de téléchargement chargé de la
fonction uploader () .
'upload.html' a un bouton de sélection de fichier et un bouton d' envoi .
a. On crée le fichier templates/upload.html comme suit :

<html>
<body>
<form action = "http://localhost:5000/uploader" method = "POST" enctype =
"multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
</body>
</html>

b. On crée le programme python upload.py comme suit :

#!/usr/bin/env python
# -*- coding: utf8 -*-
from flask import Flask, render_template, request
from werkzeug import secure_filename
app = Flask(__name__)

@app.route('/upload')
def upload_file():
return render_template('upload.html')

@app.route('/uploader', methods = ['GET', 'POST'])


def upload():
if request.method == 'POST':
f = request.files['file']
f.save(secure_filename(f.filename))
return 'Téléchargement du fichier reussi'

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

c. On lance le programme upload.py et on teste à travers un navigateur comme suit :

On clique sur Choisir un fichier pour aller sélectionner le fichier comme suit :
Après validation on obtient la capture suivante :

VI.1. Objectifs pédagogiques : Les Cookies

Un cookie est stocké sur l'ordinateur d'un client sous la forme d'un fichier texte. Son objectif est de
mémoriser et de suivre les données relatives à l'utilisation d'un client pour une meilleure expérience
des visiteurs et des statistiques de site.
Un objet Request contient un attribut de cookie. C'est un dictionnaire qui contient toutes les
variables de cookie et les valeurs correspondantes qu'un client à transmettre. En plus, un cookie
stocke également son heure d'expiration, le chemin d'accès et le nom de domaine du site.
Dans Flask, les cookies sont définis sur l'objet de réponse. Utilisez la fonction make_response ()
pour obtenir un objet de réponse à partir de la valeur de retour d’une fonction de vue. Après cela,
utilisez la fonction set_cookie () de l'objet response pour stocker un cookie.
La lecture d’un cookie est facile. La méthode get() de l' attribut request.cookies est utilisée pour
lire un cookie.
Dans l'application Flask suivante, un simple formulaire s'ouvre lorsque vous visitez l'URL '/' .
a. On crée le fichier templates/cookies.html comme suit :
<html>
<body>
<form action = "/cookie" method = "POST">
<p><h3>Entrer vos paramètres de connexion</h3></p>
<p>Login :<input type = 'text' name = 'login'/></p>
<p>Password<input type = 'text' name = 'pass'/></p>
<p><input type = 'submit' value = 'Connexion'/></p>
</form>
</body>
</html>

Le formulaire est envoyé à l'URL '/cookie'. La fonction de vue associée qui définit le login et le
password de l'utilisateur

b. On crée le programme python cookies.py comme suit :


from flask import Flask, request, make_response, render_template
app = Flask(__name__)

@app.route('/')
def index():
return render_template('cookies.html')

@app.route('/cookie', methods = ['POST', 'GET'])


def cookie():
if request.method == 'POST':
login = request.form['login']
password = request.form['pass']
resp = make_response(render_template('readcookies.html'))
resp.set_cookie('login', login )
resp.set_cookie('pass', password )
return resp

@app.route('/affichecookie')
def affichecookie():
login = request.cookies.get('login')
password = request.cookies.get('pass')
return '<h3>Bonjour votre vos parametres de connexion sont :'+login+' '+password+'</h3>'

if __name__ == '__main__':
app.run(debug = True)
c. On crée le fichier templates/readcookies.html pour afficher les cookies comme suit :

<!doctype html>
<html>
<body>
<h2><a href = "/affichecookie">Afficher les cookies</a></h2>
</body>
</html>

On lance le programme cookies.py et on teste à travers un navigateur comme suit :

On renseigne le login et le mot de passe comme suit :

Après validation on obtient la page suivante :

On clique sur afficher les cookies comme suit :


VI.3. Objectifs pédagogiques :Session
Contrairement à un cookie, les données de session sont stockées sur le serveur. La session est
l'intervalle de temps lorsqu'un client se connecte à un serveur et s'en déconnecte. Les données qui
doivent être conservées au cours de cette session, sont stockées dans un répertoire temporaire sur le
serveur.

Une session avec chaque client se voit attribuer un identifiant de session . Les données de la
session sont stockées au-dessus des cookies et le serveur les signe de manière cryptographique.
Pour ce cryptage, une application Flask nécessite un SECRET_KEY défini .
L'objet de session est également un objet de dictionnaire contenant des paires clé-valeur de
variables de session et des valeurs associées.
Par exemple, pour définir une variable de session 'nom d'utilisateur' , utilisez l'instruction

Session[‘username’] = ’admin’

Pour libérer une variable de session, utilisez la méthode pop () .

session.pop('username', None)

Le code suivant est une démonstration simple des travaux de session dans Flask. L'URL '/' invite
simplement l'utilisateur à se connecter, car la variable de session 'username' n'est pas définie.

a) On crée le fichier templates/session.html comme suit :

<form action = "/login" method = "post">


<p>login :<input type = "text" name ="login" /></p>
<p><input type = "submit" value = "Valider"/></p>
</form>

b) On crée le programme python session.py comme suit :

#!/usr/bin/env python
# -*- coding: utf8 -*-
from flask import Flask, session, redirect, url_for, escape, request, render_template
app = Flask(__name__)
app.secret_key = 'AlTd1@#0'

@app.route('/')
def index():
if 'login' in session:
username = session['login']
return 'Votre login est : ' + username + '<br>' + \
"<b><a href = '/logout'>Se deconnecter</a></b>"
return "Vous n etes pas connectes <br><a href = '/login'></b>" + \
"Se connecter</b></a>"
@app.route('/login', methods = ['GET', 'POST'])
def login():
if request.method == 'POST':
session['login'] = request.form['login']
return redirect(url_for('index'))
return render_template('session.html')

@app.route('/logout')
def logout():
session.pop('login', None)
return redirect(url_for('index'))

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

c) On lance le programme session.py comme suit :

d) On ouvre un navigateur comme suit :

e) On clique sur Se connecter et on renseigne le login comme suit :

f) Après validation on obtient la confirmation de la connexion comme le montre la figure


suivante :
Quelques questions à répondre
1. Quelle est la différence entre un formulaire classique et un formulaire destiné à parcourir
une machine pour envoyer un fichier ?
2. Quel est le rôle des cookies ?
3. Quel est le rôle des session ?
4. Quelle est la différence entre un cookie et une session ?
VII. Séquence 8 : Utilisation d’importation de modules python de base données dans Flask
L’utilisation des base de données étant très importante dans le Web Service nous abordons, dans
cette séquence les modules classiques de Python pour accéder à des base de données de type Sqlite
et MySQL sans passer par un module spécifique de flask.
Une attention particulière sera accordée à la différence entre les syntaxes des requêtes à utiliser sur
les bases selon qu’elle est de type Sqlite ou MySQL.
VII.1 Utilisation de la base de données SQLite
Python a un support intégré pour SQlite . Le module SQlite3 est livré avec la distribution Python.
Dans cette section, nous verrons comment une application Flask interagit avec SQLite.
Prérequis :
Installer le paquet sqlite3 pour la gestion des bases de données SQLite comme suit :

On écrit le programme python sqlitecreate.py pour créer une base de données SQLite
'database.db' et créez-y une table d'étudiants.
import sqlite3
conn = sqlite3.connect('database.db')
print "Opened database successfully";
conn.execute('CREATE TABLE etudiants (nom TEXT,prenom TEXT, addr TEXT, ville
TEXT, mpass TEXT)')
print "Table created successfully";
conn.close()

On l’exécute comme suit pour créer la base et la table nécessaires :


Installer le logiciel sqlitebrowser pour visualiser la base comme suit :

On lance sqlitebrowser en précisant le nom de la base à visualiser :

Les étapes seront les suivantes :


a. Création du fichier templates/accueil.html comme suit :
<!doctype html>
<html>
<body>
<h2><a href = "/entrernouveau">Ajouter un nouvel etudiant</a></h2>
<h2><a href = "/list">Lister les etudiant</a></h2>
</body>
</html>
b. Création du formulaire d’ajout d’étudiant templates/etudiantsqlite.html comme suit :
<html>
<body>
<form action = "{{ url_for('addrec') }}" method = "POST">
<h3>Information Etudiant</h3>
Nom<br>
<input type = "text" name = "nom" /></br>
Prenom<br>
<input type = "text" name = "prenom" /></br>
Adresse<br>
<textarea name = "add" ></textarea><br>
Ville<br>
<input type = "text" name = "ville" /><br>
Mot de passe<br>
<input type = "text" name = "mpass" /><br>
<input type = "submit" value = "valider" /><br>
</form>
</body>
</html>

c. Création du fichier templates/list.html pour l’affichage des étudiants comme suit :


<!doctype html>
<html>
<body>
<table border = 1>
<thead>
<td>Nom</td>
<td>Prenom</td>
<td>Adresse</td>
<td>Ville</td>
<td>Mot de Passe</td>
</thead>
{% for row in rows %}
<tr>
<td>{{row["nom"]}}</td>
<td>{{row["prenom"]}}</td>
<td>{{row["addr"]}}</td>
<td> {{ row["ville"]}}</td>
<td>{{row['mpass']}}</td>
</tr>
{% endfor %}
</table>
<a href = "/">Aller page accueil</a>
</body>
</html>
d. Création du programme python sqlite.py comme suit :
from flask import Flask, render_template, request
import sqlite3 as sql
app = Flask(__name__)
@app.route('/')
def home():
return render_template('accueil.html')
@app.route('/entrernouveau')
def new_student():
return render_template('etudiantsqlite.html')
@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
if request.method == 'POST':
try:
nom = request.form['nom']
prenom = request.form['prenom']
addr = request.form['add']
ville = request.form['ville']
mpass = request.form['mpass']
with sql.connect("database.db") as con:
cur = con.cursor()
cur.execute("INSERT INTO etudiants (nom,prenom,addr,ville,mpass)VALUES
(?,?,?,?,?)",(nom,prenom,addr,ville,mpass) )
con.commit()
msg = "Enregistrement reussi"
except:
con.rollback()
msg = "erreur insertion "
finally:
return render_template("resultsqlite.html",msg = msg)
con.close()
@app.route('/list')
def list():
con = sql.connect("database.db")
con.row_factory = sql.Row
cur = con.cursor()
cur.execute("select * from etudiants")
rows = cur.fetchall();
return render_template("list.html",rows = rows)

if __name__ == '__main__':
app.run(debug = True)
e. Création du fichier templates/resultsqlite.html qui affiche le résultat comme suit :
<!doctype html>
<html>
<body>
resultat d ajout : {{ msg }}
<h2><a href = "\">Aller page accueil</a></h2>
</body>
</html>

f. On exécute le programme sqlite.py comme suite

On lance un navigateur comme suit

On clique sur ajouter un nouvel étudiant et on renseigne les champs comme suit :
Après validation on obtient la confirmation d’ajout et on clique sur Aller page d’accueil pour
retourner à la page d’accueil comme suit :

En cliquant Lister les étudiants on a leur liste comme suit :

NB : Nous avons intégré tout d’abord l’étudiant latyr ndiaye sans capture avant d’intégrer l’étudiant
Amadou Bory Diallo.
VII.2 Utilisation de base de données Mysql
On installe le module python-mysqldb pour pouvoir utiliser une base de données dans un
programme python comme suit :

a. On se connecte au serveur mysql pour créer la base de données ecole et la table etudiants comme
suit :

b. On copie le programme sqlite.py et on modifie la partie connexion à la base de données comme


suit :
c. On crée le programme python mysql.py comme suit :
from flask import Flask, render_template, request
import MySQLdb as db
app = Flask(__name__)
con = db.connect('192.168.1.136','bouki','passer','test')
@app.route('/')
def home():
return render_template('index.html')
@app.route('/entrernouveau')
def new_student():
return render_template('etudiant.html')
@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
if request.method == 'POST':
nom = request.form['nom']
prenom = request.form['prenom']
addr = request.form['add']
ville = request.form['ville']
mpass = request.form['mpass']
with con:
cur = con.cursor()
requete = cur.execute("insert into etudiant(nom,prenom,addr,ville,mpass) values (%s,
%s,%s,%s,%s)", (nom,prenom,addr,ville,mpass))
if requete:
return 'Enregistrement reussi'
@app.route('/list', methods=['GET'])
def list():
with con:
cur = con.cursor()
requete = cur.execute("select * from etudiant")
rows = cur.fetchall()
return render_template("list.html",rows = rows)

if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0", port=int("5000"))
c. On crée le fichier templates/list.html comme suit :
<!doctype html>
<html>
<body>
<table border = 1>
<thead>
<td>Nom</td>
<td>Prenom</td>
<td>Adresse</td>
<td>Ville</td>
<td>Mot de Passe</td>
</thead>
{% for row in rows %}
<tr>
<td>{{row[0]}}</td>
<td>{{row[1]}}</td>
<td>{{row[2}}</td>
<td> {{ row[3]}}</td>
<td>{{row[4}}</td>
</tr>
{% endfor %}
</table>
<a href = "/">Aller page accueil</a>
</body>
</html>

d. On lance le programme mysql.py et on teste l’ajout d’un nouvel étudiant et l’affichage de la liste
d’étudiants

Après validation on obtient la confirmation d’ajout et on clique sur Aller page d’accueil pour
retourner à la page d’accueil comme suit :
En cliquant Lister les étudiants on a leur liste comme suit :

VIII. Séquence 9 : Extensions flask : Mail, WTF, Sqlite, SQLAlchemy


Dans cette séquence nous allons faire appel à quelques modules importants de flask permettant de
gérer l’envoi de mail, le contrôle des champs de formulaire, l’utilisation de base de données,
utilisation d’AJAX.
Le module de flask RESTful qui permet de développer des API sera développé est aussi évoqué

VIII.1 Les Extensions du flask


Flask est souvent qualifié de micro-framework, car une fonctionnalité principale inclut WSGI et un
routage basé sur Werkzeug et un moteur de modèle basé sur Jinja2 . En outre, la structure Flask
prend en charge les cookies et les sessions, ainsi que les assistants Web tels que JSON , les fichiers
statiques, etc. Évidemment, cela ne suffit pas pour le développement d'une application Web à part
entière. C'est là que les extensions Flask entrent en jeu. Les extensions de flask donnent une
extensibilité au framework Flask.
Il existe un grand nombre d'extensions Flask disponibles. Une extension Flask est un module
Python, qui ajoute un type de fonctionnalité spécifique à l'application Flask. Flask Extension
Registry est un répertoire d'extensions disponibles. Les extensions peuvent être téléchargées par l'
utilitaire pip .
On peut citer quelques extensions intéressantes de flask :
• Flask Mail - fournit une interface SMTP à l'application Flask
• Flask WTF - ajoute le rendu et la validation de WTForms
• Flask SQLAlchemy - ajoute le support SQLAlchemy à l'application Flask
• Flask Sijax - Interface pour Sijax - Bibliothèque Python / jQuery qui rend AJAX facile à
utiliser dans les applications Web
• Flask RESTful – permet de développer des API
Chaque type d'extension fournit généralement une documentation détaillée sur son utilisation.
Puisqu'une extension est un module Python, vous devez l'importer pour pouvoir l'utiliser. Les
extensions de flask sont généralement appelées flask-nomExtention.
Pour importer une extention on utilise :

from flask_ nomExtention import [class, function]

Pour les versions de Flask ultérieures à 0.7, vous pouvez également utiliser la syntaxe -

from flask.ext import NomExtension

Pour cette utilisation, un module de compatibilité doit être activé. Il peut être installé en lançant
flaskext_compat.py

import flaskext_compat
flaskext_compat.activate()
from flask.ext import NomExtension

VIII.1.1. Objectifs pédagogiques :Gestion des formulaires à l’aide de l’extension WTF

L'un des aspects essentiels d'une application Web consiste à présenter une interface utilisateur à
l'utilisateur. HTML fournit une balise <form> , utilisée pour concevoir une interface. Les éléments
d’ un formulaire tels que la saisie de texte, la radio, la sélection, etc. peuvent être utilisés de
manière appropriée.
Les données saisies par un utilisateur sont soumises sous forme de message de requête HTTP au
script côté serveur par la méthode GET ou POST.
• Le script côté serveur doit recréer les éléments de formulaire à partir des données de requête
http. En pratique, les éléments de formulaire doivent donc être définis deux fois, une fois en
HTML et une autre fois dans le script côté serveur.
• L'utilisation d'un formulaire HTML présente un autre inconvénient: il est difficile (voire
impossible) de rendre les éléments de formulaire de manière dynamique. HTML lui-même
ne fournit aucun moyen de valider la saisie d'un utilisateur.
C’est là que WTForms , une bibliothèque de formulaires, de rendu et de validation flexible, est très
pratique. L'extension Flask-WTF fournit une interface simple avec cette bibliothèque WTForms .
En utilisant Flask-WTF , nous pouvons définir les champs de formulaire dans notre script Python
et les restituer à l’aide d’un modèle HTML. Il est également possible d'appliquer une validation au
champ WTF .
Voyons comment cette génération dynamique de HTML fonctionne.
Tout d'abord, l'extension Flask-WTF doit être installée.
pip install flask-WTF

Le package installé contient une classe Form , qui doit être utilisée en tant que parent pour un
formulaire défini par l'utilisateur.
Le package WTforms contient les définitions de divers champs de formulaire. Certains champs de
formulaire standard sont répertoriés ci-dessous.

Numéro Paramètre de description


1 TextField : Représente <input type = 'text'> élément de formulaire HTML
2 BooleanField : Représente <input type = 'checkbox'> élément de formulaire
HTML
3 DecimalField : Champ de texte pour l'affichage d'un nombre avec des décimales
4 IntegerField : TextField pour afficher l'entier
5 RadioField : Représente <input type = 'radio'> élément de formulaire HTML
6 SelectField : Représente un élément de formulaire sélectionné
7 PasswordField : Représente <input type = 'password'> élément de formulaire
HTML
8 SubmitField : Représente <input type = 'submit'> élément de formulaire

9 TextAreaField : Représente <testarea> élément de formulaire html

a. On crée une classe forms.py comme suit :

from flask_wtf import Form


from wtforms import TextField, IntegerField, TextAreaField, SubmitField, RadioField,
SelectField

from wtforms import validators, ValidationError

class ContactForm(Form):
name = TextField("Donnez votre nom",[validators.Required("saisir nom")])
Gender = RadioField('Gender', choices = [('M','Homme'),('F','Femme')])
Address = TextAreaField("Adresse")

email = TextField("Email",[validators.Required("saisir votre email adresse."),


validators.Email("saisir votre email adresse.")])

Age = IntegerField("age")
language = SelectField('Langage', choices = [('cc', 'C++'),
('py', 'Python'),('php','PHP'),('ja','java'),('la','Laravel')])

submit = SubmitField("Envoyer")

b. On crée le programme formexemple.py comme suit :

from flask import Flask, render_template, request, flash


from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'flask'

@app.route('/contact', methods = ['GET', 'POST'])


def contact():
form = ContactForm()

if request.method == 'POST':
if form.validate() == False:
flash('Tous les champs sont obligatoires.')
return render_template('contact.html', form = form)
else:
return render_template('success.html')
elif request.method == 'GET':
return render_template('contact.html', form = form)

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

c. On crée le fichier templates/contact.html comme suit :

<!doctype html>
<html>
<body>
<h2 style = "text-align: center;">Contact Form</h2>

{% for message in form.name.errors %}


<div>{{ message }}</div>
{% endfor %}

{% for message in form.email.errors %}


<div>{{ message }}</div>
{% endfor %}

<form action = "http://localhost:5000/contact" method = post>


<fieldset>
<legend>Contact Form</legend>
{{ form.hidden_tag() }}
<div style = font-size:20px; font-weight:bold; margin-left:150px;>
{{ form.name.label }}<br>
{{ form.name }}
<br>
{{ form.Gender.label }} {{ form.Gender }}
{{ form.Address.label }}<br>
{{ form.Address }}
<br>
{{ form.email.label }}<br>
{{ form.email }}
<br>
{{ form.Age.label }}<br>
{{ form.Age }}
<br>
{{ form.language.label }}<br>
{{ form.language }}
<br>
{{ form.submit }}
</div>
</fieldset>
</form>
</body>
</html>

d. On crée le fichier templates/success.html comme suit :

<!doctype html>
<html>
<body>
<p>
Les informations envoyees avec succes !
</p>
</body>
</html>

On lance le programme python formexemple.py comme suit :

On ouvre un navigateur pour accéder au formulaire et on remplit les différents champs comme suit :
Après validation on obtient la confirmation de l’envoi des informations comme suit :

VIII.1.2. Objectifs pédagogiques :Envoi de mail via l’extension Mail de flask


Une application Web est souvent nécessaire pour pouvoir envoyer des messages aux utilisateurs.
L'extension Flask-Mail facilite la configuration d'une interface simple avec n'importe quel serveur
de messagerie.
Au début, l'extension Flask-Mail doit être installée à l'aide de l'utilitaire pip.

pip install Flask-Mail

Ensuite, Flask-Mail doit être configuré en définissant les valeurs des paramètres d'application
suivants :

Numéro Paramètre de description


1 MAIL_SERVER : Nom / adresse IP du serveur de messagerie
2 MAIL_PORT :Numéro de port du serveur utilisé
3 MAIL_USE_TLS :Activer / désactiver le chiffrement de la couche de sécurité de
transport
4 MAIL_USE_SSL : Activer / désactiver le cryptage Secure Sockets Layer
5 MAIL_DEBUG : Support de débogage. L'état par défaut du débogage de l'application
Flask est défini par défaut.
6 MAIL_USERNAME : Nom d'utilisateur de l'expéditeur
7 MAIL_PASSWORD : mot de passe de l'expéditeur
8 MAIL_DEFAULT_SENDER : définit l'expéditeur par défaut
9 MAIL_MAX_EMAILS : Définit le nombre maximum de mails à envoyer
10 MAIL_SUPPRESS_SEND : Envoi supprimé si app.testing est défini sur true
11 MAIL_ASCII_ATTACHMENTS : Si défini sur true, les noms de fichiers attachés
convertis en ASCII

Le module flask-mail contient les définitions des classes importantes suivantes.


Il gère les exigences de messagerie électronique. Le constructeur de classe prend la forme suivante :

la forme suivante -

flask-mail.Mail(app = None)

Le constructeur prend l'objet application Flask en tant que paramètre.


Quelques méthodes de la classe mail

Numéro Paramètre de description


1 send() : Envoie le contenu de l'objet de classe Message
2 Connect() : Ouvre la connexion avec l'hôte de messagerie
3 send_message() : Envoie l'objet du message
Il encapsule un message électronique. Le constructeur de la classe message a plusieurs paramètres
comme suit :

flask-mail.Message(subject, recipients, body, html, sender, cc, bcc,

reply-to, date, charset, extra_headers, mail_options, rcpt_options)

Méthodes de classe de message


attach () - ajoute une pièce jointe au message. Cette méthode prend les paramètres suivants -
• filename - nom du fichier à joindre
• content_type - type de fichier MIME
• data - données de fichier brutes
• disposition - disposition du contenu, le cas échéant.
add_recipient () - ajoute un autre destinataire au message

Dans l'exemple suivant, le serveur SMTP du service gmail de Google est utilisé comme
MAIL_SERVER pour la configuration Flask-Mail.

a. On crée le programme python mail.py comme suit :

from flask import Flask


from flask_mail import Mail, Message
app =Flask(__name__)
app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'licence2019ec2lt@gmail.com'
app.config['MAIL_PASSWORD'] = 'mot de passe '
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)
@app.route("/mail/<string:destinataire>/<string:objet>/<string:message>")
def index(destinataire,objet,message):
msg = Message(objet, sender = 'licence2019ec2lt@gmail.com', recipients = [destinataire])
msg.body = message
mail.send(msg)
return "Envoye"

if __name__ == '__main__':
app.run(debug = True)
b. Notez que les fonctionnalités d'insécurité intégrées au service Gmail peuvent bloquer cette
tentative de connexion. Vous devrez peut-être diminuer le niveau de sécurité. Connectez-vous à
votre compte Gmail et visitez ce lien pour autoriser :
https://myaccount.google.com/lesssecureapps?pli=1

c. On teste dans un navigateur comme suit :

http://localhost:5000/mail/latyrndiaye86@gmail.com/reunion/toto tape nama

Latyr Ndiaye vérifie la réception du mail sur son compte gmail avec l’objet réunion et le contenu du
message toto tape nama :
Séquence 10 : Gestion de Multimédia : photo, vidéo, audio
Dans cette séquence montre tout simplement comment gérer du multimédia à travers des templates
grâce à l’utilisation de balise classiques de HTML audio, vidéo et image
Intégration du multimédia dans un programme flask

Cas 1 : Vidéo
a. On crée le fichier template templates/video.html comme suit :

<!DOCTYPE html>
<html>
<head>
<title>Video Example</title>
</head>
<body>
<h2>Serving video files from Flask template</h2>
<video width="320" height="240" controls>
<source src={{ url_for('static', filename="demo.mp4") }} type="video/mp4">
</video>
</body>
</html>

b. On crée le programme python video.py comme suit :

from flask import Flask, render_template

app = Flask(__name__, static_folder='static')

@app.route('/')
def index():
return render_template('video.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)

c. On copie la vidéo dans le dossier static portant le nom demo.mp4

d. On lance le programme video.py et on teste via un navigateur comme suit :


Cas2 : Images

a. On crée un fichier templates/image.html comme suit :

<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<img src="{{ user_image }}" alt="User Image" width=100 height=100>
</body>
</html>

b. On crée le programme python video.py comme suit :


from flask import Flask, render_template
import os

PEOPLE_FOLDER = os.path.join('static', 'people_photo')

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = PEOPLE_FOLDER

@app.route('/')
@app.route('/index')
def show_index():
full_filename = os.path.join(app.config['UPLOAD_FOLDER'], 'shovon.jpg')
return render_template("image.html", user_image = full_filename)

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

c. On copie l’image sous le nom shovon.jpg dans le dossier static/people_photo/

d. On lance le programme python image.py et on teste via un navigateur comme suit :

Programme permettant d’inscrire les étudiants avec leur photo dans une base de données et les
afficher
a. On crée le fichier templates/index.html comme suit :
<!doctype html>
<html>
<body>
<h2><a href = "/entrernouveau">Ajouter un nouvel etudiant</a></h2>
<h2><a href = "/list">Lister les etudiants</a></h2>
</body>
</html>

b. On crée le fichier templates/etudiant.html comme suit :

<html>
<body>
<form action = "{{ url_for('addrec') }}" method = "POST" enctype = "multipart/form-
data">
<h3>Information Etudiant</h3>
Nom<br>
<input type = "text" name = "nom" /></br>
Prenom<br>
<input type = "text" name = "prenom" /></br>
Photo<br>
<input type = "file" name = "image" /></br>

<input type = "submit" value = "valider" /><br>


</form>
<a href = "/">Aller page accueil</a>
</body>
</html>

c. le fichier templates/list.html comme suit :

<!doctype html>
<html>
<body>
<table border = 1>
<thead>
<td>Nom</td>
<td>Prenom</td>
<td>Photo</td>
</thead>

{% for row in rows %}


<tr>
<td>{{row[0]}}</td>
<td>{{row[1]}}</td>
<td><img src="static/photo/{{ row[2] }}" alt="User Image" width=100
height=100/></td>
</tr>
{% endfor %}
</table>
<a href = "/">Aller page accueil</a>
</body>
</html>

d. on crée le programme python mysql.py comme suit :

from flask import Flask, render_template, request


from werkzeug import secure_filename
import os
import MySQLdb as db

app = Flask(__name__)

UPLOAD_FOLDER = 'static/photo'
ALLOWED_EXTENSIONS = set(['txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'])

con = db.connect('192.168.1.136','bouki','passer','test')

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

#rows = []

@app.route('/')
def home():
return render_template('index.html')

@app.route('/entrernouveau')
def new_student():
return render_template('etudiant.html')

@app.route('/addrec',methods = ['POST', 'GET'])


def addrec():
if request.method == 'POST':
nom = request.form['nom']
prenom = request.form['prenom']
image = request.files['image']
filename = secure_filename(prenom+'.'+nom+'_'+image.filename)
image.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
with con:
cur = con.cursor()
requete = cur.execute("insert into etudiant(nom,prenom,image) values (%s,%s,%s)",
(nom,prenom,filename))
if requete:
return 'Enregistrement reussi'

@app.route('/list', methods=['GET'])
def list():
with con:
cur = con.cursor()
requete = cur.execute("select * from etudiant")
rows = cur.fetchall()
return render_template("list.html",rows = rows)

if __name__ == '__main__':
app.run(
debug=True,
host="0.0.0.0",
port=int("5000")
)

e. On lance le programme python et on teste à travers un navigateur comme suit :

f. On clique sur Ajouter un nouvel etudiant et on renseigne ses informations comme suit :

g. On clique sut Aller page accueil pour revenir à la page d’accueil puis on clique sur lister les
étudiants et on obtient le résultat comme suit :
Séquence 11 : Paquetage et déploiement
Dans cette séquence nous expliquons comment créer un paquetage de son projet une fois développé
pour le livrer et être installé avec les dépendances.
L’accent est mise sur l’utilisation de WSGI en vue de déployer l’application sur un web classique tel
que apache2.
III.1 Flask – Déploiement d’une application à l’aide WSGI sous apache2

a. On installe le module libapache2-mod-wsgi comme suit :

# apt-get install libapache2-mod-wsgi

b. On crée un site virtuel dans /etc/apache2/sites-available/api.conf comme suit :

<VirtualHost *:80>
ServerName monapi.rtn.sn
WSGIScriptAlias / /var/www/html/Api/app_api.wsgi
</VirtualHost>

c. On copie le dossier du projet nommé app_api dans /var/www/html/Api


d. On active le site virtuel accessible sur la web par monapi.rtn.sn avec la commande suivante :
a2ensite api.conf
e. On crée le fichier /var/www/html/Api/app_api.wsgi comme suit :

import sys
sys.path.append('/var/www/html/Api/app_api')
sys.stdout = sys.stderr
from crudApi import app as application

f. On redémarre le serveur apache comme suit :


service apache2 restart

NB : N’ayant pas de serveur DNS nous avons résolu le nom monapi.rtn.sn dans le fichier
/etc/hosts comme suit :
127.0.0.1 monapi.rtn.sn
g. On teste l’hébergement de notre application python sous apache comme suit

III.2 Flask – Déploiement d’une application à l’aide WSGI sous apache2 avec template

a. On installe le module libapache2-mod-wsgi comme suit :

# apt-get install libapache2-mod-wsgi

b. On crée un site virtuel dans /etc/apache2/sites-available/testdeploy.conf comme suit :

<VirtualHost *:80>
ServerName test-deploy.rtn.sn
WSGIScriptAlias / /var/www/html/depmysql/depmysql.wsgi
</VirtualHost>
c. On copie le dossier du projet avec template nommé depmysql dans /var/www/html/depmysql
d. On active le site virtuel accessible sur la web par test-deploy.rtn.sn avec la commande suivante :
a2ensite testdeploy.conf
e. On crée le fichier /var/www/html/depmysql/depmysql.wsgi comme suit :

import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0, '/var/www/html/depmysql')
from mysql import app as application

NB : le mysql de la ligne 5 du fichier /var/www/html/depmysql/depmysql.wsgi correspond au


nom du programme python.

f. On redémarre le serveur apache comme suit :


service apache2 restart
NB : N’ayant pas de serveur DNS nous avons résolu le nom test-deploy.rtn.sn dans le fichier
/etc/hosts comme suit :
127.0.0.1 test-deploy.rtn.sn
g. On teste l’hébergement de notre application python sous apache comme suit

Séquence 12 : Étude du module RESTFul de flask


Cette séquence introduit les concepts de base de l’architecture REST et donne un exemple concret
de développement d’une API REST en respectant le modèle CRUD (Create, Read, Update, Delete).
Cette séquence montre aussi l’importance de séparer les fonctions faisant les manipulations dans un
fichier module et la partie purment flask qui les utilise.
Developpement d’API RESTfull avec Flask

I.1- Définition d’API et quelques cas d’utilisation

L’API, pour Application Programming Interface, est la partie du programme qu’on expose
officiellement au monde extérieur pour manipuler celui-ci. L’API est au développeur ce que l’User
Interface est à l’utilisateur. Cette dernière permet d’entrer des données et de les récupérer la sortie
d’un traitement. Initialement, une API regroupe un ensemble de fonctions ou méthodes, leurs
signatures et ordre d’usage pour obtenir un résultat.

La mise en place d’une API permet d’opérer une séparation des responsabilités entre le client et le
serveur. Cette séparation permet donc une portabilité et évolutivité grandement améliorées. Chaque
composant peut évoluer séparément car il n’y a aucun logique du côté du serveur. Ainsi on peut
imaginer une refonte totale de la charte graphique du site web sans devoir modifier le code côté
serveur ou sur les autres clients (mobiles par exemple).

API REST ou API SOAP ?


Il existe actuellement deux types d’architecture très utilisées pour les API : Simple Object Access
Protocol (SOAP)et Representational State Transfer (REST).
SOAP et REST sont deux solutions permettant à un client d’accéder à des services web. Le choix
d'abord peut sembler facile, mais parfois il peut être étonnamment difficile. D’un côté, SOAP,
initialement développé par Microsoft, est un protocole d'accès aux services Web qui existe depuis
un certain temps. De l’autre, l’architecture REST est la novuelle venue. Elle vise à résoudre certains
problèmes rencontrés avec SOAP et donner la possibilité de mettre en place une méthode vraiment
simple afin d’accéder à des services web.
Les deux techniques ont des problèmes à prendre en compte au moment de décider quel protocole
utiliser. Avant d'aller plus loin, il est important de préciser que même si SOAP et REST présentent
des similitudes en utilisant le protocole HTTP, SOAP est un ensemble plus rigide que REST. REST
a une architecture qui ne nécessite pas de traitement et qui est naturellement plus flexible. SOAP et
REST reposent sur des règles bien établies que tout le monde a accepté de respecter dans l'intérêt de
l'échange d'informations.

I.2- Définition de API REST

Une API REST se doit d’être sans état ou stateless en anglais. La communication entre le client et le
serveur ne doit pas dépendre d’un quelconque contexte provenant du serveur. Ainsi, chaque requête
doit contenir l’ensemble des informations nécessaires à son traitement. Cela permet au de traiter
indifféremment les requêtes de plusieurs clients via de multiples instances de serveurs.

Selon le modèle de maturité de Richardson il existe quatre grands niveaux d’évaluation d’une API.
Au plus on atteint un niveau élevé au plus notre API est considérée comme RESTful et respecte ce
qu’on appelle communément les “bonnes pratiques”.

Le niveau 0 (le niveau le plus bas mis en avant par le modèle de Richardson) est une API qui qu’on
ne peut pas qualifier d’API REST. Ce niveau s’apparente davantage à ce que l'on peut retrouver
dans une API de type SOAP, une architecture un peu démodée, beaucoup moins populaire que
l’architecture RESTful. Considéré comme la base minimale, Il s'agit de n'utiliser qu'un seul point
d'entrée pour communiquer avec l'API. Une URI unique est mise en place, comme par exemple
“/api”, de même qu'une seule méthode HTTP n’est utilisée afin d’effectuer ses demandes, il s’agit
de POST. Toutes les requêtes sont de type POST et sont effectués vers la même URI.
Le niveau 1 concerne les différentes ressources et exige en premier lieu que chacune d’elle puisse
être distinguée séparément. Cela signifie que l’on ne possède donc plus une unique URI mais une
URI pour chaque ressource que l’on souhaite manipuler. Et pour aller plus loin, il est nécessaire de
réfléchir dès le début à la manière nous allons mettre en place ces différents URIs. Prenons notre
cas pour un exemple concret : avec une API nous permettant de manipuler des athlètes, nous
souhaitons mettre en place un CRUD (Create, Read, Update, Delete) soit Créer, Lire, Mettre à jour
et Supprimer. Quels sont les points d’entrée qu’il faudra définir afin de pouvoir réaliser ces
actions ? Il n’existe pas de solution unique, mais voici une façon de faire qui respecterait le niveau 1
du modèle de Richardson :
• Création/Ajout d’un athlète : /athlète/create

• Pour la lecture d’athlètes, nous aurions l’URI suivante /athlète pour obtenir la liste des
athlètes et /athlète/{identifiant-unique} afin d’accéder au profil d’un athlète spécifique par
exemple
• Pour la mise à jour des informations d’un athlète cela pourrait être : /athlète/{identifiant-
unique}/update
• Pour la suppression, rien de bien compliqué il suffit de changer le verbe de l’URI précédente
avec /athlète/{identifiant-unique}/delete

Dernière étape nécessaire afin d’atteindre le 2ème palier, il faut maintenant associer les différentes
méthodes HTTP en fonction de l’action que nous souhaitons effectuer grâce à l’API. En reprenant
l’exemple de tout à l’heure, il nous suffit d’associer une méthode HTTP (POST, GET, PUT et
DELETE) à l’action souhaitée. Ainsi il est toujours possible de réaliser un CRUD et les URIs
devraient ressembler à ceci :

• Création/Ajout d’un athlète : POST /athlètes


• Pour la lecture d’athlète GET /athlètes pour obtenir la liste des athlètes et /athlète/
{identifiant-unique} afin d’accéder au profil d’un athlète spécifique par exemple.
• Pour la mise à jour des informations d’un athlète cela pourrait être : PUT /athlètes/
{identifiant-unique}
• Pour la suppression, DELETE /athlètes/{identifiant-unique}
Les actions ne font plus partie de l'URI, elles sont directement effectuées selon la méthode HTTP
utilisée, le protocole est ainsi utilisé à sa pleine capacité. Par ailleurs, dernier point à vérifier et à
mettre en place, il s’agit des codes status.
Pour chaque réponse renvoyée par l’API, un code doit être envoyé, ce code correspond à l’état de la
requête et dépend de la réussite ou non de celle-ci

Les codes status les plus courants que l’on retrouve généralement sur le web sont :
• 200 OK Tout s'est bien passé

• 201 Created La création de la ressource s'est bien passée (il n’est pas rare que les attributs de
la nouvelle ressource soient aussi renvoyées dans la réponse. Dans ce cas, l’URL de cette
ressource nouvellement créée est ajouté via un header Location )
• 204 No content Même principe que pour la 201, sauf que cette fois-ci, le contenu de la
ressource nouvellement créée ou modifiée n'est pas renvoyée en réponse
• 304 Not modified Le contenu n'a pas été modifié depuis la dernière fois qu'elle a été mise en
cache
• 400 Bad request La demande n'a pas pu être traitée correctement

• 401 Unauthorized L'authentification a échoué

• 403 Forbidden L'accès à cette ressource n'est pas autorisé

• 404 Not found La ressource n'existe pas

• 405 Method not allowed La méthode HTTP utilisée n'est pas traitable par l'API

• 406 Not acceptable L’API est dans l’incapacité de fournir le format demandé par les en têtes
Accept. Par exemple, le client demande un format (XML par exemple) et l'API n'est pas
prévue pour générer du XML
• 500 Server error Le serveur a rencontré un problème.

Il est important de configurer ces statuts et dans le mesure du possible de fournir une explication
avec chaque code, de cette façon il est plus facile de résoudre un problème si l’on rencontre un code
d’erreur 400 et qu’un message nous explique le problème.
Il existe de nombreux autres critères afin d’établir une API répondant aux normes REST, cependant
les points cités ci-dessus sont les plus importants et présentent les avantages de ce type d’API. Le
modèle de Richardson met en évidence un troisième niveau d’exigence afin de créer une API
parfaitement RESTful, cependant nous avons décidé que dans notre cas, le deuxième niveau serait
amplement suffisant et permettrait de travailler avec une API fonctionnelle tout en ayant une
architecture soignée. Le but recherché est de pouvoir fournir les données et d’établir le lien entre la
logique de présentation se trouvant côté client et nos données se trouvant dans notre base de
données.
Application :

Nous vous fournissons le contenu de l’api de gestion de compte bancaire.


a. On crée un fichier appelé crud.py (module) dans lequel nous définissons toutes les fonctions qui
font tous les traitements dont on a besoin dans l’api.

#!/usr/bin/env python
# -*- coding: utf8 -*-
import MySQLdb as db

con = db.connect('192.168.1.165','bouki','passer','sgbs')

def create(prenom,nom,code,numcompte,solde):
with con:
cur = con.cursor()
requete = cur.execute("insert into client(prenom,nom,code,numcompte,solde) values (%s, %s,
%s, %s,%s)",(prenom,nom,code,numcompte,solde))
con.commit()
return 'insertion reussie'

def readall():
with con:
cur = con.cursor()
requete = cur.execute("select * from client")
info=cur.fetchall()
if info:
for i in info:
print i[0], i[1], i[2], i[3], i[4]

def read(numcompte, code):


with con:
cur = con.cursor()
requete = cur.execute("select * from client where numcompte= %s",(numcompte,))
info = cur.fetchone()
if requete:
code1 = info[2]
if code == code1:
return info[0]+' '+info[1] + ' le solde de votre compte est de : '+str(info[4])
else:
return 'informations incorrectes'

def update(numcompteexp,code,numcomptedest,montant):
with con:
cur = con.cursor()
requete = cur.execute("select * from client where numcompte= %s",(numcompteexp,))
info = cur.fetchone()
if requete:
code1 = info[2]
solde = info[4]
if code == code1:
if solde > montant:
solde = solde - montant
requetedest = cur.execute("select * from client where numcompte= %s",
(numcomptedest,))
infodest= cur.fetchone()
montantdest = infodest[4]
if requetedest:
requete_uptade_exp = cur.execute("update client set solde = %s where numcompte=
%s",(solde,numcompteexp))
requete_uptade_dest = cur.execute("update client set solde = %s where numcompte=
%s",(montantdest+montant,numcomptedest))
return 'Transfert avec succee'
else:
return 'destinataire inconnu'
else:
return 'solde insuffisant'

def delete(numcompte):
with con:
cur = con.cursor()
requete = cur.execute("delete from client where numcompte= %s",(numcompte,))
if requete:
return 'Suppression reussie'
else:
return 'Echec suppression'

b . On crée le fichier crudApi.py qui va faire appel à des fonctions définies dans le module crud.py.

Vous remarquez que le module crud a été importé dans notre api à la ligne 4.
Notre api importe aussi le module Restplus de flask qui permet de déployer des applications
respectant l’architecture REST tout en fournissant la documentation.

#!/usr/bin/env python
# -*- coding: utf8 -*-
from flask import Flask, request
import crud
from flask_restplus import Resource, Api, fields

app = Flask(__name__)
api = Api(app, version='1.0', title="API de Consultation", description="Cette API permet de
consulter son compte bancaire",)

parser = api.parser()

@api.route('/api/v1.0/EC2LT_infos/<string:prenom>/<string:nom>/<int:code>/<string:numco
mpte>/<int:solde>/')
class Create(Resource):
def get(self,prenom,nom,code,numcompte,solde):
'''Ajouter compte'''
return crud.create(prenom,nom,code,numcompte,solde)

@api.route('/api/v1.0/EC2LT_infos/<string:numcomptelire>/<int:codelire>/')
class Read(Resource):
def get(self,numcomptelire,codelire):
'''Lire compte'''
return crud.read(numcomptelire,codelire)

@api.route('/api/v1.0/EC2LT_infos/<string:numcompteexp>/<int:codeexp>/<string:numcomp
tedest>/<int:soldeupdate>/')
class Update(Resource):
def get(self,numcompteexp,codeexp,numcomptedest,soldeupdate):
'''Transfert de solde'''
return crud.update(numcompteexp,codeexp,numcomptedest,soldeupdate)

@api.route('/api/v1.0/EC2LT_infos/<string:numcomptedelete>/')
class Delete(Resource):
def get(self,numcomptedelete):
'''Suppression de compte'''
return crud.delete(numcomptedelete)

if __name__ == '__main__':
app.run(
debug=True,
host="0.0.0.0",
port=int("5000")
)

Séquence 13 : Sécurité API : authentification


Pour des raisons de sécurité il est important qu’une API intègre la partie authentification et
autorisation c’est l’objet de cette séquence qui vous montre comment atteindre cet objectif.
Séquence 14 : Synthèse sur les interfaces d’utilisation d’API
Grâce à l’utilisation des formulaires, templates et inclusion de code python dans les templates il est
possible de créer une interface d’utilisation d’une API voir ().
En plus de cela nous montrons l’importance de connaissance en HTML, CSS et PHP en vue de
développer des interfaces conviviales d’utilisation d’une API.

Conclusion Générale
Deux métiers :
• Développeur d’API avec des connaissances en python, Flask, HTML, CSS et JavaScript
• Développeur d’interface d’utilisation d’API avec des connaissances en HTML, CSS et PHP

Vous aimerez peut-être aussi