exercices: premier template, première route, premier passage de paramètres à un template

vidéo (niveau NSI) pour bien démarrer flask si on va trop vite et dont s’inspire ces exercices : FLASK (Un prof de NSI)

lien sur son code source

exercice 1 : rôle des routes


  1. modifier la route
@app.route('/')
@app.route('/hello')
def hello_world():  # put application's code here
    return 'Hello World!<a href="hello">lien hello</a>  &nbsp; <a href="/heure"> heure </a>'
  1. ajouter une autre route qui appelle un template
@app.route('/heure')
def heure():
    date_heure = datetime.datetime.now()
    h = date_heure.hour
    m = date_heure.minute
    s = date_heure.second
    return render_template('index_demo.html', h=h,min=m,sec=s )
  1. Ajouter la bibliothèque datetime sous l’instruction from flask import Flask. Importer plusieurs fonctions dans la bibliothèque flask.
from flask import Flask, request, render_template, redirect, url_for, abort  # application WSGI
import datetime
  1. créer le template (fichier) index_demo.html dans le dossier templates


  1. utiliser le snippet html:5 puis dans la balise <body>
    <p> heure = {{ h }} , minute = {{ m }}, seconde  = {{ sec }}</p>

    <br>
    <a href="/">home</a>

Il faut corriger le nom de la variable : remplacer m par min


exercice 2 : récupérer les paramètres dans un lien et les champs input dans un formulaire

vidéo (niveau NSI) pour bien démarrer flask dont est inspiré cet exercice

nous allons utiliser un tableau de dictionnaires de données

liste_etudiants = [
    {'id':1,'nom':'tom', 'groupe':'A1'},
    {'id':2,'nom':'enzo', 'groupe':'A1'},
    {'id':3,'nom':'laurence', 'groupe':'A2'},
    {'id':4,'nom':'theo', 'groupe':'A2'},
    {'id':5,'nom':'mehdi', 'groupe':'B1'}
]
  1. ajouter ce tableau au début du fichier d’application flask après avoir importé les bibliothèques

  2. créer une route /etudiant/show qui appelle la fonction show_etudiants

  3. à l’intérieur du dossier templates, créer un dossier etudiant ; dans le dossier templates/etudiant/ créer une vue (un fichier) show_etudiant.html

  4. dans la fonction show_etudiants, passer en paramètre la liste liste_etudiants avec comme nom etudiants

  5. afficher la liste des étudiants dans le fichier templates/etudiant/show_etudiant.html

<h1>listes des étudiants</h1>

{{ etudiants }}
  1. ajouter un lien sur la page d’accueil dans le fichier templates/index_demo.html
    <br>
    <a href="/etudiant/show">etudiants</a>
  1. afficher la liste des étudiants dans un tableau ; il faut utiliser une boucle
<table>
    {% for etudiant in etudiants %}
         <tr>
                <td>{{ etudiant }}</td>
           </tr>
        {% endfor %}
</table>

code branche 1

  1. remplacer la ligne qui affiche chaque étudiant avec le code ci-dessous
<table class="table">
    <thead class="thead-dark">
    <tr>
        <th>id</th><th>nom</th><th>groupe</th>
    </tr>
    </thead>
    {% for etudiant in etudiants %}
    <tr>
        {# commentaires : autre notation possible, on affiche un element du dictionnaire               
                <td>{{ etudiant['id'] }}</td><td>{{ etudiant['nom'] }}</td><td>{{ etudiant['groupe'] }}</td>
        #}
        <td>{{ etudiant.id }}</td><td>{{ etudiant.nom }}</td><td>{{ etudiant.groupe }}</td>
    </tr>
    {% endfor %}
</table>
  1. tester avec un tableau de dictionnaire d’étudiant vide dans le fichier app.py

  2. afficher la liste des étudiants si le tableau n’est pas vide en intégrant le code ci-dessous dans le template show_etudiant.html

    {% if etudiants | length >= 1 %}
       ...
    {% else %}
           <h2> la liste des étudiants est vide</h2> 
    {% endif %}

autre exemple : cours NSI

Sur les outils JetBrains
Remarque : Ctrl+alt+I => indentation
Ctrl+r => rechercher/remplacer
Dans le contrôleur Ctrl+clic sur le nom d’un template dans le contrôleur (app)

utilisation de lien

  1. au bout des 2 routes ajouter un paramètre : l’identifiant de l’étudiant ?id= suivi de la valeur de l’identifiant de l’étudiant.

  2. ajouter un lien pour ajouter un étudiant avant l’affichage du tableau

<a href="/etudiant/add" >ajouter un étudiant</a>


....


<td>
    <a href="/etudiant/edit?id={{ etudiant.id }}"   class="btn btn-success">editer</a>&nbsp;
    <a href="/etudiant/delete?id={{ etudiant.id }}"   class="btn btn-success">supprimer</a>
</td>

passage de paramètres

  1. créer 3 routes /etudiant/add , /etudiant/delete et /etudiant/edit dans le fichier de l’application flask associées à 3 fonctions add_etudiant , delete_etudiant et edit_etudiant
@app.route('/etudiant/add')
def add_etudiant():
    print('''affichage du formulaire pour saisir un étudiant''')
    return render_template('etudiant/add_etudiant.html')

@app.route('/etudiant/delete')
def delete_etudiant():
    print('''suppression d'un étudiant''')

@app.route('/etudiant/edit')
def edit_etudiant():
    print('''affichage du formulaire pour modifier un étudiant''')
    return render_template('etudiant/edit_etudiant.html')

utilisation de paramètres issus de liens

voici le code HTML généré par ChatGPT pour saisir les informations d’un étudiant :


(code généré en saisissant le prompt : donner le code HTML d’un formulaire en utilisant le framework bootstrap 5 pour saisir les informations du tableau python : )

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Formulaire d'Étudiant</title>
    <!-- Inclure Bootstrap 5 CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.7.0/dist/css/bootstrap.min.css">
</head>
<body>
    <div class="container mt-4">
        <h1>Formulaire d'Étudiant</h1>
        <form>
            <!-- Champs pour saisir les informations de l'étudiant -->
            <div class="mb-3">
                <label for="nom" class="form-label">Nom de l'étudiant :</label>
                <input type="text" class="form-control" id="nom" placeholder="Entrez le nom de l'étudiant" required>
            </div>
            <div class="mb-3">
                <label for="groupe" class="form-label">Groupe de l'étudiant :</label>
                <select class="form-select" id="groupe" required>
                    <option value="A1">A1</option>
                    <option value="A2">A2</option>
                    <option value="B1">B1</option>
                </select>
            </div>
            <button type="submit" class="btn btn-primary">Enregistrer</button>
        </form>
    </div>

    <!-- Inclure Bootstrap 5 JS (pour les fonctionnalités supplémentaires) -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.7.0/dist/js/bootstrap.min.js"></script>
</body>
</html>
  1. créer 2 templates etudiant/add_etudiant.html et etudiant/edit_etudiant.html

  2. dans les 2 fonctions delete_etudiant et edit_etudiant, afficher à l’aide de l’instruction print dans le terminal le paramètre reçu de nom id. Utiliser la fonction print(request.args).

  3. pourdelete_etudiant , une erreur est générée car il n’y a pas de réponse retournée au navigateur (pas de return)

redirection

  1. à la fin de la fonction delete_etudiant faire une redirection sur la route show_etudiants avec l’instruction :


return redirect('/etudiant/show')

  1. ajouter le code ci-dessous dans la fonction delete_etudiant et edit_etudiant
    id=request.args.get('id')
    message='paramètre dans l URL : '+id
    print(message)

* Pour récupérer les paramètres dans l’URL d’une page HTML (méthode GET ), utiliser la méthode de l’objet request : request.args.get avec comme clé le nom du paramètre

  1. pour la fonction edit_etudiant, ajouter le code ci-dessous puis passer
    id=request.args.get('id')
    if id != None and id.isnumeric():
        indice = int(id)
        etudiant=liste_etudiants[indice-1]
    else:
        etudiant=[]
  1. Passer en paramètre l’étudiant sélectionné au template edit_etudiant.html . Afficher dans chaque champ input de ce template la valeur de l’information concernant l’étudiant (id, nom , groupe) .

code branche 2 – étape 23 tester et modifier le code sur github

utilisation des paramètres issus d’un formulaire

  1. créer 2 routes /etudiant/add et /etudiant/edit dans le fichier de l’application flask associées à 2 fonctions valid_add_etudiant et valid_edit_etudiant
@app.route('/etudiant/add', methods=['POST'])
def valid_add_etudiant():
    print('''ajout de l'étudiant dans le tableau''')
    return redirect('/etudiant/show')

@app.route('/etudiant/edit', methods=['POST'])
def valid_edit_etudiant():
    print('''modification de l'étudiant dans le tableau''')
    return redirect('/etudiant/show')
  1. ajouter dans les balises <form> des 2 formulaires des templates les attributs action="/etudiant/add" method="post" ou les attributs action="/etudiant/edit" method="post"

  2. indiquer pour les routes des 2 fonctions add_etudiant et edit_etudiant la méthode pour la route : il faut ajouter dans l’annotation , methods=['GET']

  3. afficher dans le terminal dans les 2 fonctions valid_add_etudiant et valid_edit_etudiant les paramètres reçu de chaque formulaire print(request.form)

  4. créer un message avec les informations pour ajouter un étudiant

nom = request.form.get('nom')
groupe = request.form.get('groupe')
message = 'nom :'+nom+' - groupe :'+groupe    
print(message)
  1. tester et modifier l’erreur : ChatGPT a oublier l’attribut name= dans les balises <input> et <select>

  2. créer un message avec les informations pour modifier un étudiant

id = request.form.get('id')
nom = request.form.get('nom')
groupe = request.form.get('groupe')
message = 'nom :'+nom+' - groupe :'+groupe+' pour l etudiant d identifiant :'+id   
print(message)
  1. dans le formulaire pour modifier les données d’un étudiant il faut un champ caché avec l’identifiant de l’étudiant
<input type="hidden" name="id" value="{{ etudiant.id }}" >

Dans ce formulaire, il manque l’attribut value={{etudiant.nom}} dans la balise <input> pour que ce champ soit initialisé avec le nom de l’étudiant à éventuellement modifier.

Afficher la valeur du groupe {{etudiant.groupe}} ; pour la liste déroulante, c’est plus compliqué, le code est présenté dans le tp suivant.


fichiers “static”


  1. Supprimer la route /hello et la fonction hello_world ; associer la route / à la fonction show_etudiants
  2. Supprimer la route /heure et la fonction heure

Il n’est pas possible dans le dossier templates d’utiliser des fichiers CSS des images ….

  1. placer le contenu du fichier ressources suivant dans le fichier static


Les fichiers STATIC sont tous des fichiers dont le contenu ne changent jamais : les fichiers CSS (vos styles, bootstrap), les images, les fichiers javascript


Ce dossier s’appelle aussi public dans d’autres framework(s) (symfony laravel …)


Dans flask pour utiliser le contenu de ces fichiers dans les templates il faut utiliser la fonction : {{ url_for('static', filename='dossier_dans_static/nom_du_fichier') }}


  1. modifier le fichier templates show_etudiants.html (gabarits) avec les liens ci-dessous
<link rel="icon"  href="{{ url_for('static', filename='iconeweb.ico') }}" />

<link rel="stylesheet" href="{{ url_for('static', filename='mes_styles.css') }}" >
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" >


....
<img src="{{ url_for('static', filename='image_iut.jpeg') }}" alt="image iut"  />


....


<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.js') }}"></script>

code branche final

Un gabarit (template) est un fichier dont le contenu va être modifié par l’application. L’application va passer des paramètres (données) à la vue : la vue est renvoyée au client

principe du MVC

heritage et liste déroulante

  1. heritage
<!doctype html>
<html lang="fr">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    {% block title %}
        <title>layout</title>
    {% endblock %}
    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" >
    {% block stylesheets %}
        <link rel="stylesheet" href="{{ url_for('static', filename='mes_styles.css') }}" >
        {#<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.css') }}" >#}
    {% endblock %}
</head>
<body>
{% include('_nav.html') %}

{% block body %}
    <h2 style="color:blue">layout.html</h2>  
{% endblock %}
{% block javascripts %}
    {#<script src="{{ url_for('static', filename='bootstrap/js/bootstrap.js') }}"></script>#}
{% endblock %}
</body>
</html>
<nav class="menu">
    <a href="/etudiant/show"> etudiants </a>  -
    <a href="/groupe/show"> groupes </a>  -
</nav>
<hr>
{% extends 'layout.html' %}

{% block title %}
    <title>gestion des étudiants</title>
{% endblock %}

{% block body %}

{% endblock %}
  1. messages flash
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
    {% for categorie, message in messages %}
    <div role="alert" class="alert {{ categorie }}">
           Information : <strong>{{ message }}</strong>
    </div>
    {% endfor %}
{% endif %}
{% endwith %}
flash(message, 'alert-warning')
flash(message, 'alert-success')
  1. liste déroulante
liste_etudiants = [
    {'id':'1','nom':'tom', 'groupe_id':'1'},
    {'id':'2','nom':'enzo', 'groupe_id':'1'},
    {'id':'3','nom':'laurence', 'groupe_id':'2'},
    {'id':'4','nom':'theo', 'groupe_id':'2'},
    {'id':'5','nom':'mehdi', 'groupe_id':'3'}
]

liste_groupes = [
    {'id': '1', 'libelle': 'A1'},
    {'id': '2', 'libelle': 'A2'},
    {'id': '3', 'libelle': 'B1'},
    {'id': '4', 'libelle': 'B2'}
]
<select name="id_groupe" required>
    <option value="">Sélectionner un groupe</option>
    {% for groupe in groupes %}
         <option value="{{ groupe.id }}"> {{ groupe.libelle }} </option>
    {% endfor %}
</select>
<select name="id_groupe" required>
    {% for groupe in groupes %}
    <option value="{{ groupe.id }}"
            {% if etudiant.groupe_id is defined and groupe.id == etudiant.groupe_id %}selected{% endif %}
    > {{ groupe.libelle }} </option>
    {% endfor %}
</select>
    return render_template('etudiant/add_etudiant.html', groupes=liste_groupes)
    return render_template('etudiant/edit_etudiant.html', groupes=liste_groupes)
 <td>{{ etudiant.id }}</td><td>{{ etudiant.nom }}</td><td>{{ etudiant.groupe }}</td>

et la récupération des données dans les fonctions appellées lors de la validation des formulaires

nom = request.form.get('nom')
id_groupe = request.form.get('id_groupe')
message = 'nom :'+nom+' - id_groupe :' + id_groupe    
print(message)
id = request.form.get('id')
nom = request.form.get('nom')
id_groupe = request.form.get('id_groupe')
message = 'nom :'+nom+' - id_groupe :' + id_groupe + ' pour l etudiant d identifiant :' + id   
print(message)

annexe

en cas de problème avec pycharm (blocage) : supprimer le dossier .cache/jetbrains/pycharm


probleme version python