Le framework Flask¶§
Pourquoi un framework ?¶§
WSGI est minimaliste¶§
- Son objectif : la compatibilité
- entre différents serveurs Web
- entre différents types d’application
→ plus grand dénominateur commun
Inconvénients¶§
- beaucoup de code boilerplate
- pas de fonctionalités de haut niveau
Flask : premiers pas¶§
Hello World Flask¶§
from flask import Flask
app = Flask(__name__)
@app.route("/")
def root():
return "Hello world"
Explications¶§
app
est une application Flask; elle est entre-autre homogène à une fonction WSGI, donc elle peut être utilisée comme la fonctionapplication
vue au cours précédent.- La fonction
root
est appelée une vue. Elle retourne une chaîne de caractères, qui sera le contenu de la réponse. Par défaut, le statut de la réponse est 200, et le type de contenu est HTML, encode en UTF-8. On verra plus tard comment générer d’autres types de réponses. - La ligne qui précède la fonction
root
est un décorateur python. Il sert à indiquer l’URL pour laquelle cette vue doit être utilisée.
Routes¶§
En développement Web, on apelle route une URL ou un ensemble d’URLs conduisant à l’exécution d’une fonction donnée.
Dans Flask, les routes sont déclarées via le décorateur
app.route
, comme dans l’exemple ci-dessus.Une route peut être paramétrée, auquel cas le paramềtre sera passé à la fonction vue :
@app.route("/hello/<name>") def hello(name): return "Hello %s" % name
Note
Il est possible d’avoir plusieurs paramètres,
par exemple /hello/<a>/<b>
.
Il est également possible d’imposer un type aux paramètres,
par exemple /user/<int:ident>
.
Génération d’URL¶§
Les routes permettent à Flask de trouver la vue correspondant à une URL, mais également de faire l’inverse, à savoir de reconstruire l’URL d’une vue donnée.
La fonction
flask.url_for
prend en paramètre le nom d’une vue (le nom de la fonction, dans une chaîne de caractères), avec ses éventuels paramètres, et retourne l’URL correspondante. Exemples :# avec les routes des exemples précédents url_for('root') # → "/" url_for('hello', name="John") # → "/hello/John"
on peut passer à
url_for
des paramètres supplémentaires (i.e. non spécifiés par la vue), lesquels seront ajoutés en paramètres d’URL :url_for('hello', name="John", foo="bar") # → /hello/John?foo=bar
le paramètre
_external
peut être mis à True pour géréner une URL absolu :url_for('root', _external=True) # → http://localhost:5000/
Exemple d’utilisation :
@app.route("/about")
def about():
return """<a href="%s">Retour à la page d'accueil</a>""" % \
url_for('root')
Indice
url_for
rend le code plus facile à maintenir :
si on décide de changer l’URL d’une vue,
il suffit de changer le paramètre de app.route
,
et toutes les autres vues contenant des liens vers elle s’adapteront automatiquement.
Ressources statiques¶§
Une application Web ne se limite pas aux contenus HTML générés par les vues; on a également besoin de ressources statiques (CSS, images...).
Dans Flask, il est possible de stocker des fichiers dans un répertoire
static
, situé dans le même répertoire que le fichier Python définissant l’application.L’URL de ces fichiers est donnée par la fonction
url_for
:url_for("static", filename="nom_du_fichier.css")
Où est ma requête ?¶§
- Contrairement aux fonctions WSGI, les vues Flask ne reçoivent pas directement l’information contenue dans la requête HTTP.
- Cette information est accessible via l’objet
flask.request
. - Cet objet possède un certain nombre d’attributs, dont :
method
généralement GET ou POSTheaders
un dictionnaire(-like) contenant les en-têtesenviron
l’environnement WSGI sous-jacent (pour les nostalgiques ;-)
cf. http://flask.pocoo.org/docs/0.12/api/#incoming-request-data
Serveur de développement¶§
Comme indiqué ci-dessus, l’objet
app
est homogène à une fonction WSGI. On peut donc réutiliser le script serveur vu au cours précédent.Mais Flask fournit son propre serveur de développement, directement dans la méthode
run
de l’application. Le script serveur devient donc :from mon_projet import app app.run(debug=True)
- Le mode
debug
offre notamment des fonctions avancées, notamment :- le recharchement automatique des fichiers python en cas de modification,
- l’affichage des exceptions dans le navigateur,
- la possibilité d’interagir avec le code python depuis le navigateur en cas d’erreur.
Templates Jinja2¶§
Qu’est-ce qu’un template?¶§
Un template, ou “modèle”, est un fichier dont certaines parties seront remplacées à l’exécution.
Voici un exemple minimaliste :
<p>Hello {{name}}</p>
où la partie entre doubles-accolades sera remplacée par le contenu de la variable
name
, par exemple :<p>Hello world</p>
Templates en Flask¶§
Flask utilise le système de templates Jinja2, qui permet de générer n’importe quel format textuel (HTML, CSS...).
Les templates sont stockés dans un répertoire
templates
, situé dans le même répertoire que le fichier Python définissant l’application.Pour appliquer un template, il suffit d’appeler la fonction
flask.render_template
en lui passant + le nom du template (relativ au répertoiretemplates
), et + la liste des variables utilisées par le template :@app.route("/hello/<n>") def hello(n): return render_template("hello.html", name=n)
Substitution¶§
- Dans une template Jinja2,
les doubles-accolades
{{ }}
servent à indiquer une substitution. - Elles peuvent contenir un nom de variable,
mais également des expressions plus complexes,
par exemple
{{reqest.method}}
ou{{row[0]}}
. - Certaines variables sont transmises automatiquement aux templates,
notamment l’object requête
request
.
Structures de contrôle¶§
- Jinja2 offre des structures de contrôles (condition, boucle) similaires à celles de Python.
- Elles sont encadrées par les symboles
{% %}
.
{% if elements %}
<ul>
{% for e in elements %}
<li><a href="{{e.link}}">{{e.name}}</li>
{% endfor %}
</ul>
{% else %}
<p>Aucun élément</p>
{% endif %}
Héritage¶§
layout.html
:
<!DOCTYPE html><html>
<head><title>Le titre du site</title></head>
<body>
<h1>Le titre du site</h1>
{% block content %}{% endblock %}
<footer>©2017 Université Lyon 1</footer>
</body></html>
hello.html
:
{% extends "layout.html" %}
{% block content %}
<p>Hello {{name}}</p>
{% endblock %}
Note
- La directive
extends
permet à un template d’hériter d’un autre. - La directive
block
permet- au template parent de définir des zones personalisables, et
- au template enfant de donner un contenu aux blocs définis par son parent.
Formulaires¶§
Réponses personalisées¶§
Erreur¶§
Pour déclencher une réponse d’erreur (code HTTP 4xx),
on peut utiliser la fonction flask.abort
en lui passant le code de statut à retourner
(et éventuellement, un message personnalisé).
Exemple :
abort(403, "Cette operation n'est pas autorisee")
Indice
La fonction abort
lève une exception
(ce qui explique qu’elle ne nécessite pas de return
).
Cette exception est interceptée par l’application Flask,
qui la transforme en réponse HTTP avec le code d’erreur associé.
Redirecton¶§
Pour rediriger le client vers une autre URL (code HTTP 3xx),
on peut utiliser la fonction flask.redirect
.
Exemple :
return redirect(url_for("root"))
Pour aller plus loin¶§
Lorsqu’une vue retourne une chaîne de caractères (ce que nous avons vu jusqu’à maintenant), l’application Flask génère automatiquement une réponse standard (statut 200, contenu de type HTML).
Il est également possible pour une vue de retourner directement
un objet Response
,
dont on peut alors personaliser les méta-données.
Cet objet peut être produit grâce à la fonction flask.make_response
.
Exemple :
resp = make_response(render_template("hello.html", name=n))
resp.headers["Cache-control"] = "max-age=3600"
return resp
Note
La fonction redirect
vue ci-avant retourne un objet Response
.