Flask
*****
.. figure:: data/flask.png
Flask est un framework web beaucoup plus évolué que Bottle.
Il reste compact mais comporte beaucoup plus de possibilité de bottle (a priori on ré-invente moins la roue)
Il prend en charge nativement les templates **Jinja2**
Il possède de plus un ensemble de plugin qui permet rapidement de lui rajouter ce qui lui manque
Installation
============
Rien de plus simple avec pip
.. code-block:: bash
pip install flask
Premier exemple
===============
Commençons par un simple "hello word"...
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run()
Pour tester ce code, il suffit juste de lancer la commande suivante.
Et d’ouvrir le navigateur sur l’URL qui sera affichée dans la console.
.. code-block:: bash
$ python app.py
* Running on http://127.0.0.1:5000/
Pour l'instant si on compare Flask et Bottle cela ne fait pas beaucoup de différence.
Et heureusement puisqu'ils respectent tous les deux le PEP de python sur les framework web.
Debugger
========
Flask possède un debugger intégré très performant puisqu'il permet de lancer via
un naviguateur web une console python (accessible via chaque ligne du résultat du debugger)
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
# une erreur ici
a = 1/0
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
.. figure:: data/flask_debug.png
On peut aussi activer le debug via l'utilisation une variable globale
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask
# Flask configuration
DEBUG = True
app = Flask(__name__)
app.config.from_object(__name__)
@app.route("/")
def hello():
# une erreur ici
a = 1/0
return "Hello World!"
if __name__ == "__main__":
app.run()
.. note::
On peut utiliser n'importe quelle variable en majuscule de l'objet utilisé dans from_object.
On peut ainsi passer le path d'un fichier log ou celui d'une base de donnée
On récupère les variables via le code
.. code-block:: python
app.config['NAME_OF_VARIABLE']
Logger
======
Flask possède de façon native un handler de logger ... on peut donc facilement rajouter des loggers
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
from flask import Flask
# Flask configuration
DEBUG = True
SERVER_NAME = '0.0.0.0:5001'
LEVEL = logging.INFO
app = Flask(__name__)
app.config.from_object(__name__)
@app.route('/')
def hello():
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
app.logger.info('Info')
return "Hello World!"
if __name__ == '__main__':
handler = logging.StreamHandler()
handler.setLevel(app.config['LEVEL'])
app.logger.addHandler(handler)
app.run()
.. warning::
si on passe le DEBUG a False on ne voit que les errors et les warnings plus les infos
Ajout de fonction pre et post
=============================
Comme pour bottle on peut décorer les appels ... mais Flask possède des décorateurs pré-défini
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
from flask import Flask
# Flask configuration
DEBUG = True
SERVER_NAME = '0.0.0.0:5001'
LEVEL = logging.INFO
app = Flask(__name__)
app.config.from_object(__name__)
@app.before_request
def before_request():
app.logger.warning('before call')
@app.teardown_request
def teardown_request(exception):
app.logger.warning('after call')
@app.route('/')
def hello():
app.logger.warning('A warning occurred (%d apples)', 42)
app.logger.error('An error occurred')
app.logger.info('Info')
return "Hello World!"
if __name__ == '__main__':
handler = logging.StreamHandler()
handler.setLevel(app.config['LEVEL'])
app.logger.addHandler(handler)
app.run()
Filtrage des formulaires et des réponses
========================================
.. code-block:: python
@app.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'GET':
# afficher le formulaire
else:
# traiter les données reçues
# afficher : "Merci de m'avoir laissé un message !"
Les sessions
============
Les sessions sont donc un moyen simplifié et plus sécurisé de retenir des informations pour vos visiteurs. Les sessions utilisent deux choses distinctes :
* Un cookie placé chez le client, pour identifier sa session.
* Des données stockées sur le serveur, reliées à cette même session.
Pour fonctionner, nous aurons besoin d'importer l'objet session :
.. code-block:: python
from flask import session
Cet objet s'utilise ensuite de la même manière qu'un dictionnaire Python.
L'avantage est qu'on peut lire et écrire dedans, on ne passe donc plus par les objets requête et réponse.
Voilà l'équivalent du code avec les cookies transposé dans une version utilisant session à la place :
.. code-block:: python
@app.route('/')
def index():
if 'pseudo' in session:
return "C'est un plaisir de se revoir, {pseudo} !".format(pseudo=session['pseudo'])
else:
session['pseudo'] = 'Luc'
return "Bonjour, c'est votre première visite ?"
Le défaut des sessions est qu'on ne peut pas choisir de période d'expiration différente pour chaque variable qu'on stocke dans la session.
Par défaut, la session sera effacée quand le visiteur fermera son navigateur.
Si on veut qu'elle dure plus longtemps, il faut placer session.permanent = True après sa création.
Elle vivra alors un mois.
Pour changer cette durée, il faut modifier la configuration de l'objet app :
.. code-block:: python
app.config['PERMANENT_SESSION_LIFETIME'] = 3600 # la session dure une heure
On peut stocker n'importe quoi dans session : entiers, chaînes, listes, objets, dictionnaires, etc.
Cependant, dans le cas des listes et des dictionnaires (et de tout type mutable plus généralement),
il faut notifier la session lorsqu'on les modifie, en positionnant à True l'attribut modified :
.. code-block:: python
session['mon_panier'].append('appareil photo') # mon_panier est une liste
session.modified = True
Pour finir, lorsqu'on désire supprimer une variable de la session, on utilise la méthode pop() de la session :
.. code-block:: python
session.pop('pseudo', None)
.. note::
Le deuxième paramètre (None) est là uniquement pour éviter une erreur s'il n'y a pas de variable 'pseudo' dans la session.
Les templates
=============
.. code-block:: python
#! /usr/bin/python
# -*- coding:utf-8 -*-
from flask import Flask
app = Flask(__name__)
@app.route('/')
def accueil():
mots = ["bonjour", "à", "toi,", "visiteur."]
return render_template('accueil.html', titre="Bienvenue !", mots=mots)
if __name__ == '__main__':
app.run(debug=True)
.. note::
penser dans les template a ne pas utiliser d'adresse en dur mais d'utiliser url_for()
.. code-block:: html
Création d'un site statique
===========================
.. code-block:: python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from flask import Flask
import flask
# Flask configuration
DEBUG = True
PATH_HTML = 'C:/Users/f.aoustin/Google Drive/mydoc/build/html'
PATH_INDEX = 'index.html'
app = Flask(__name__)
app.config.from_object(__name__)
@app.route("/")
def index():
return flask.send_from_directory(app.config['PATH_HTML'],app.config['PATH_INDEX'])
@app.route("/")
def static_web(path):
return flask.send_from_directory(app.config['PATH_HTML'],path)
if __name__ == "__main__":
app.run()
Plugins
=======
flask-login
+++++++++++
Généralement lors de la création d'une applicatino web une des premiere fonctionnalité est la gestion de l'accès à cette dernière.
Flask possède un plugin qui gère cela pour nous: flask-login
.. code-block:: python
pip install flask
pip install flask-login
on va par la suite créer cette arborescence
::
dir
|__ myapp.py
|__ myapp.cfg
|__ templates
| |__ login.html
|__ statics
|__ css
|__ fonts
|__ js
| |__ myjs.js
|__ less
|__ scss
|__ admin.html
|__ protected.html
On utilisera les modules font-awesomes et nos modules propres de design (cf autre billet: design web)
admin.html
.. code-block:: html
test admin
logoutindex