.. _TD2Aecodebuterflaskrst: =========================== 2A.eco - Débuter avec Flask =========================== .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/td2a_eco/TD2A_eco_debuter_flask.ipynb|*` Pour aller vite, `Flask `__ est un framework de développement web en Python. Il en existe d’autres, le plus connu d’entre eux est `Django `__. Ce notebook la création d’un site web à usage principalement privé. En alliant le langage de programmation Python et un système de templates très riche, on peut créer assez facilement une application. Forcément, plus l’application que vous rêvez de réaliser sera compliquée et plein de fonctionnalités, plus le temps qu’il vous faudra pour la coder sera long. Mais avec `Flask `__, on peut déjà rapidement obtenir des résultats, sans trop se perdre. Mais attention, `Flask `__ ne fait pas tout : si vous voulez aboutir à quelque chose de sérieux en web-app, vous finirez par utililser `Django `__. Mais `Django `__ est très lourd à apprendre, tandis que Flask ressemble beaucoup à ce qu’on a utilisé pendant les cours. Contrairement à `Django `__ qui fait beaucoup de choses tout seul (ORM, validations formulaires, back-end admin…), `Flask `__ reste simple et c’est à vous de lui coder/rajouter ces composants à la main. Il est aussi très utilisé et ne risque pas de disparaître de sitôt. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: Comment ça marche ? ------------------- Pour commencer, disons qu’un site web n’est qu’un simple programme exécuté sur un ordinateur. Si vous voulez une présentation détaillée de l’écosystème du web, `le résumé de code school `__ est complet et très clair. Quand vous vous rendez sur ce site web, vous êtes ce qu’on appellera un client, et l’ordinateur où est exécuté ce site web est appelé le serveur. Durant le TD, nous utiliserons le même ordinateur pour faire les deux : le site web sera donc situé sur votre propre machine. Ce qui veut dire que votre application ne sera disponible que pour vous, on dit encore *“en local”*. Pour communiquer avec le site internet, le client envoie des requêtes au serveur, en gros en lui donnant une page (une url) le client demande au serveur une chose bien précise. Pour faire simple, tout se joue dans l’adresse mise dans le navigateur. L’adresse https://github.com/sdpython/ensae_teaching_cs est composée de plusieurs parties : - ``https`` : c’est le protocole on ne va pas en parler ici - ``github.com`` : c’est le nom du domaine - ``sdpython/ensae_teaching_cs`` : c’est le chemin de la page web demandée, aussi appelé *“route”*. Dans le TD comme tout se passe sur notre ordinateur, on n’a pas de nom de domaine; Il est remplacé par localhost par convention. Pour accéder à la page appelée “/unepage”, nous devrons donc entrer dans notre navigateur : http://localhost/unepage Et petite subtilité, un serveur HTTP peut fonctionner sur différents ports. Par défaut, le serveur HTTP intégré à Flask fonctionne sur le port 5000, il faut donc le préciser dans l’adresse du navigateur. Ce qui donne au final l’adresse http://localhost:5000/unepage pour accéder à la page /unepage de notre application. Première page internet avec Flask --------------------------------- Exécutez le code ci-dessous après avoir “décommenté” les deux dernières lignes. Allez à la page http://localhost:5000/. Pour quitter, il faut interrompre le kernel en cliquant sur *kernel > interrupt*. .. code:: ipython3 from flask import Flask # pip install flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" # if __name__ == "__main__": # app.run() Explication du code pas à pas ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ce code commence par importer le module Flask. .. code:: ipython3 from flask import Flask On donne ensuite un nom à l’application ici ce sera app .. code:: ipython3 app = Flask(__name__) Ensuite vient la partie cruciale : définir une page (ou route) avec flask @app.route permet de préciser à quelle adresse ce qui suit va s’appliquer. Ici comme on est sur la page d’accueil, on met juste (“/”) @app.route("/") Ensuite vient la fonction hello() qui va s’éxécuter sur la page “/”. On dit simplement que quand on arrive sur la page définie par la route juste au dessus, on va en même temps appeler la fonction hello(). Ici ça va donc afficher “Hello World” quand on arrive sur la page “/”. .. code:: ipython3 def hello(): return "Hello World!" Cette dernière partie permet juste de faire en sorte que l’application se lance quand on lance le code dans la console ou le terminal. .. code:: ipython3 if __name__ == "__main__" and "get_ipython" not in locals(): # ne pas exécuter dans un notebook app.run() Exercice 1 ~~~~~~~~~~ Remplacez ``"Hello World !"`` par ``"ce que vous voulez"`` et affichez ce nouveau texte dans la page hébergée en local. Deuxième page internet avec Flask - sans le notebook ---------------------------------------------------- Là il faut vous armer un peu de patience. Car le problème de `Flask `__, c’est qu’on ne peut pas tout exécuter dans un notebook (le `CSS `__, les templates, etc.) On va devoir repasser par Python `Spyder `__ (ou n’importe quel éditeur de texte comme `Sublime Text `__ par exemple) et la ligne de commande. Mais pas de panique, on y va pas à pas. Les éléments nécessaires ~~~~~~~~~~~~~~~~~~~~~~~~ Les codes .py exemples ^^^^^^^^^^^^^^^^^^^^^^ Déjà, les exemples sont disponibles dans le fichier `flask_complet.zip `__. Pour chaque élément que nous regarderons il y aura un dossier correspondant. Les outils à manipuler ^^^^^^^^^^^^^^^^^^^^^^ **Sublimetex** L’éditeur le plus utilisé par les développeurs web : `Sublime Text `__. L’intérêt principal : pouvoir ouvrir dans un même éditeur de texte, des fichiers avec des langages différents (`HTML `__, `CSS `__, python), très pratique quand on code une application web. Et c’est codé en python ;) Vous pouvez télécharger `Sublime Text 3 `__ (il s’agit en théorie encore d’une version bêta, mais elle fonctionne très bien). Pour les sessions ENSAE, prenez la version portable. **Console** Pour ouvrir une invite de commandes : - sous Windows, il faut chercher *“cmd”* dans l’outil de recherche - sous Mac, utilisez spotlight (raccourci *Pomme + espace*) et chercher console La console permettra de lancer les *.py* et exécutera le script qui lancera l’application. Lancer la première page ~~~~~~~~~~~~~~~~~~~~~~~ Prenez le code hello_world.py Ouvrir la console et taper ``"python xxxxxxxx/hello_world.py"`` (en remplacant les x par le chemin de votre fichier ``hello.py``, par exemple ``C:/Téléchargements`` ou ``C:/Bureau/Python/``) Ouvrir une page du navigateur et aller à l’adresse http://localhost:5000. Vous devriez voir une page avec le texte *“Hello World”* en haut à gauche : si c’est le cas, bravo ! Vous venez de créer la première page de votre future application. .. code:: ipython3 from pyquickhelper.helpgen import NbImage NbImage("simple_hello.png") .. image:: TD2A_eco_debuter_flask_23_0.png Ajouter un peu de style à la page --------------------------------- Pour l’instant, la page est assez austère, c’est normal, on n’a pas encore défini l’ensemble des styles qui iront avec cette page. Pour cela, il faut commencer par réaliser une structure de dossiers que `flask `__ comprend. En gros, on va indiquer à `Flask `__ des templates de pages et des styles prédéfinis pour l’application. En ouvrant le dossier ``hello_color`` vous trouverez 3 éléments : - ``hello_world_green.py`` - un dossier ``static`` qui contient la feuille de style ``main.css`` - un dossier ``templates`` qui contient une page ``home.html`` La structure du dossier et le nom des dossiers ``static`` et ``templates`` sont importants : `Flask `__ sait que c’est dans ces dossiers là qu’il doit aller chercher les éléments qui l’intéressent. Si vous lancez l’application à partir de la console vous verrez qu’à présent le texte est en vert ! C’est parce qu’on a défini les styles de la page. On va passer chaque élément en détail pour bien comprendre comment ça marche. .. code:: ipython3 NbImage("green_hello.png") .. image:: TD2A_eco_debuter_flask_25_0.png Le hello_world_green.py ~~~~~~~~~~~~~~~~~~~~~~~ Par rapport au précédent ``hello_world.py``, on a modifié quelques éléments. On importe la méthode ``render_template`` qui va permettre de faire le lien entre le *.py* et la page html prédéfinie. .. code:: ipython3 #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask, render_template app = Flask(__name__) @app.route("/") def hello(): return render_template("home.html", message = "Hello World!") #if __name__ == "__main__": # app.run() Ici, au lieu de renvoyer le texte directement, on demande d’injecter dans le template de la page home le message ``Hello World``. Le template home.html ~~~~~~~~~~~~~~~~~~~~~ Dans ces lignes, il y a deux éléments importants : - l’appel au *css* pour avoir le style - l’intégration de ce que python injecte dans la page L’appel au css se fait dans la balise ```` où on indique le chemin pour accéder à la feuille de style. On intègre ce qui est envoyé grâce au caractère ``{{ }}`` ici on aura donc le message ``"Hello World"`` qui sera affiché avec un type ``h1``.

{{ message }}

Le main.css ~~~~~~~~~~~ Justement le ``h1`` dans le *css*, on lui dit à quoi il doit ressembler. On va lui donner une couleur verte et le centrer. h1 { font-size: 2em; color: green; text-align: center; } Exercice 2 ~~~~~~~~~~ Changez le texte de la variable message, passez le en rouge, texte aligné à gauche, police 1em. Pour que le style s’actualise, il faut : - modifier le *.css* - enregistrer les modifications - clic droit sur la page http://localhost:5000/ pour afficher le code source - clic sur ``static/main.css`` - actualiser cette page *(F5)* - retourner à la page http://localhost:5000/ Si vous voulez tester `d’autres styles `__\ … Naviguer entre les pages ------------------------ Pour l’instant, on a vu comment faire une page simple, maintenant on va en faire deux et comment passer de l’une à l’autre. Pour cela, ouvrez le dossier multiple_pages. Par rapport à l’exemple précédent, on a ajouté 1 template html ``'page_suivante.html'`` et modifié légèrement le code *.py* ainsi que la page ``home.html``. .. code:: ipython3 NbImage("2_pages.png") .. image:: TD2A_eco_debuter_flask_36_0.png Regardons tout ça en détail. app_two_pages.py ~~~~~~~~~~~~~~~~ .. code:: ipython3 #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask, render_template app = Flask(__name__) @app.route("/") def hello(): return render_template("home.html", message_bienvenue="Bienvenue sur la page d'accueil !") @app.route("/next") def suite(): return render_template("page_suivante.html") #if __name__ == "__main__": # app.run() Par rapport à l’exemple précédent, on a ajouté une route et une nouvelle fonction. La nouvelle route est celle d’une deuxième page à qui on applique le template html ``"page_suivante"``. Dans cet exemple, on n’injecte rien depuis python dans la page. home.html ~~~~~~~~~ La page d’accueil a été légèrement enrichie d’une ligne pour accéder à la deuxième page.

{{ message_bienvenue }}

Cliquer pour continuer On inclut un lien dans une balise a un peu passe-partout. Le ``href`` est une balise qui permet de mettre des liens et pour indiquer à `flask `__ à quelle page il doit se rendre en cliquant sur le lien il faut lui donner le nom de la **fonction** définie pour la page (pas la route !) Dans l’exemple on donne indique bien ``url_for('suite')`` et non pas ``url_for('next')``. Cliquer pour continuer page_suivante.html ~~~~~~~~~~~~~~~~~~ Elle ressemble beaucoup à la page ``home.html`` sauf qu’on n’a pas mis d’élément entre ``{{}}``. Et le lien présent dans cette page renvoie vers la page d’accueil.

Vous êtes sur la 2eme page

retourner à la page d'accueil Envoyer des informations ------------------------ A présent, on va voir comment on peut remplir un formulaire (dans notre cas, renseigner son nom dans une box). Dans le dossier ``"login"``, on a comme d’habitude, le *.py*, les templates html et le style *css*. .. code:: ipython3 NbImage("login.png") .. image:: TD2A_eco_debuter_flask_49_0.png home.html ~~~~~~~~~ Cette fois-ci on commence par regarder la page html : on voit apparaitre un nouvel élément le ``"form"`` : - On indique POST pour dire qu’on va s’en servir pour que l’utilisateur puisse fournir des informations. - On indique aussi que ce qui sera donné est considéré comme un *string* - Pour l’expérience utilisateur, on précise aussi qu’il y a un bouton *“OK”* pour envoyer le formulaire

Indiquer votre nom

login.py ~~~~~~~~ Ici on va se concentrer sur la fonction ``text_box``. Nous aimerions récupérer le message envoyé par l’utilisateur et le lui afficher. Pour récupérer les informations envoyées par l’utilisateur, on va importer une nouvelle méthode de `flask `__, la méthode ``request``. Pour cela, il faut utiliser la méthode ``"form"`` de l’objet ``request``, qui contient toutes les données du formulaire envoyé en *POST*. La méthode form est un dictionnaire qui associe la valeur à l’attribut name du champ du formulaire. En l’occurence, l’attribut name du champ texte vaut ``"text"``. Pour récupérer son contenu il faudra donc faire ``request.form['text']``. Et voilà ! Ensuite on réutilise ce qu’il a entré pour l’injecter dans une page de bienvenue. .. code:: ipython3 from flask import Flask, request, render_template app = Flask(__name__) @app.route('/') def home(): return render_template("home.html") @app.route('/', methods=['POST']) def text_box(): text = request.form['text'] processed_text = text.upper() return render_template("bienvenue.html" , message = processed_text ) #if __name__ == '__main__': # app.run() Conclusion ~~~~~~~~~~ Voilà pour la base de ce qui se passe quand on utilise le framework `Flask `__. C’est une très très courte introduction et si souhaitez approfondir vous pouvez suivre le très bon cours Openclassrooms https://openclassrooms.com/courses/creez-vos-applications-web-avec-flask/ En attendant, on va essayer de faire ensemble un questionnaire Pokemon ou Big Data, histoire d’avoir quelque chose qui fonctionne à la fin de la séance. Pour cela, ouvrez le dossier ``pokemon_big_data`` et lancer le code *.py* en ligne de commande pour voir ce que ça donne sur http://localhost:5000/.