Développer un site interactif avec formulaire et ajax

Objectifs et données

Pour commencer, on dispose sur notre serveur de :

  • 3000 extraits musicaux de 15 s

  • d'un fichier de type csv, contenant une ligne par extrait musical : 4 champs séparés par des ; groupe ;album ;titre ;chemin vers le fichier

  • d'un interpréteur python (python cgi sur apache2)

  • D'un gestionnaire de fichier en ligne pour éditer / transférer / gérer les droits des fichiers

    L'édition de fichiers pythons en ligne n'est pas aisée avec cet éditeur ( gestion de l'indentation) , pour cela on dispose également d'un accès webdav qui permet l'usage d'un éditeur plus adapté.

Le travail à réaliser :

On cherche à faire une sorte de jukebox en ligne, l'utilisateur choisira dans un premier temps le groupe, puis l'album, puis l'extrait musical à jouer .

Les objectifs liés au programme :

  • Représentation des données : types construits

    • Type dictionnaire pour passer les commandes à l'interface

    • Dictionnaires par clés / valeurs

  • Traitement de données en tables :

    • Indexation de tables

    • Recherche dans une table

    • Tri d'une table

    • Fusion d'un table

  • Interactions entre l'homme et la machine sur le Web

    • Modalités de l'interaction entre l'homme et la machine

    • Interaction avec l'utilisateur dans une page Web

    • Interaction client-serveur. Requêtes HTTP, réponses du serveur

    • Formulaire d'une page Web

Partie python : le traitement des données

Les différentes étapes

On adopte une structure de type web pour préparer la suite de la réalisation.

Comme on travaillera avec des scripts cgi python avec des formulaires, puis ajout d'ajax, autant préparer la structure et les affichages en conséquences .

Dans le répertoire cgi, on trouve deux fichiers :

  • fonctions.py contenant que l'on utilisera comme bibliothèque pour alléger la page contenant les codes

  • ressources.py qui permet de récupérer les données envoyées par les formulaires et renvoyer les réponses

Les instructions seront passées au fichier ressources via des formulaires.

On utilisera pour le fichier ressources.py des couples clefs / valeurs stockées dans un dictionnaire nommé choix. La  clef action pour l'action à réaliser , puis la variable fichier qui contiendra l'emplacement du fichier à traiter. Celui-ci ne changera pas au cours de l"activité, mais sur le prinvipe il est bon de la prévoir comme variable.

On désire extraire à partir du fichier listeok.csv dans l'ordre :

  1. La liste des artistes (action :voirArtistes)

  2. La liste des albums d'un artiste (action :voirAlbums), dans ce cas, notre dictionnaire devra également contenir l'artiste dont on veut voir les albums (artiste : artiste choisi au 1)

  3. La liste des morceaux d'un album(action :voirMorceaux), dans ce cas, notre dictionnaire devra contenir l'album choisi précédemment (album : album choisi au 2)

  4. Le morceau à jouer, Enfin ! (action :jouerMorceau) et lemorceau : . ;le morceau choisi).

Quelques exemples :

choix = {'action':'voirArtistes','fichier':'../data/listeok.csv'} pour afficher les artistes

choix = {'action':'voirMorceaux','fichier':'../data/listeok.csv','album' :'The Alice Cooper Show'}

La structure de départ

Pour commencer, on présente la structure de départ

Ci dessous , la structure de départ, attention, le serveur hébergeant les site possède ses propres ressources :

  • /nsi/components/jquery-3.3.1.min.js pour le jquery (bibliothèques javascript utilisée plus tard)

  • /nsi/components/bootstrap/css/bootstrap.min.css (bibliothèque css pour gagner du temps)

La partie WEB - comprendre le principe ..

Structures des pages

La page qui servira d'interface avec l'utilisateur : index.html

Pour l'instant le javascript est commenté

1
<!doctype html>
2
<html  lang="fr">
3
    <head>
4
        <meta charset="utf-8">
5
        <meta name="viewport" content="width=device-width, initial-scale=1">
6
        <title>Musiques </title>
7
        <link href="/nsi/components/bootstrap/css/bootstrap.min.css" rel="stylesheet">
8
	    <link rel="stylesheet" type="text/css" href="../css/default.css">
9
	    
10
    </head>
11
<body>
12
    <header>
13
  <!-- Fixed navbar -->
14
  <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
15
    <div class="container-fluid">
16
      <a class="navbar-brand" href="#">Le mini projet JBK: - page de tests </a>
17
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
18
        <span class="navbar-toggler-icon"></span>
19
      </button>
20
      <div class="collapse navbar-collapse" id="navbarCollapse">
21
        <ul class="navbar-nav me-auto mb-2 mb-md-0">
22
          <li class="nav-item">
23
            <a class="nav-link active" aria-current="page" href="../../1nsi.html">Retour accueil</a>
24
          </li>
25
          <li class="nav-item">
26
            <a class="nav-link" href="index.html">Ma page </a>
27
          </li>
28
          <li class="nav-item">
29
            <a class="nav-link disabled">Disabled</a>
30
          </li>
31
        </ul>
32
        <form class="d-flex" role="search">
33
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
34
          <button class="btn btn-outline-success" type="submit">Search</button>
35
        </form>
36
      </div>
37
    </div>
38
  </nav>
39
</header>
40
<!--
41
Début du corps de la page
42
-->
43
  <div class="container">
44
  <div class="row">
45
    <!--Colonne de gauche-->
46
    <div class="col-sm gauche">
47
      <h1> Les artistes</h1>
48
    
49
   
50
    </div>
51
    <!--colonne du milieu -->
52
    <div class="col-sm milieu">
53
     <h1> Les albums </h1>
54
    </div>
55
    <!-- colonne de droite-->
56
    <div class="col-sm droit">
57
     <h1>Les morceaux</h1>
58
    </div>
59
  </div>
60
</div> 
61
 <!--   
62
<script src="/nsi/components/jquery-3.3.1.min.js"></script>      
63
 <script src="../js/default.js"></script>
64
-->
65
</body>
66
67
</html>

Pour commencer, on va utiliser le fichier tests.html, pour mettre au point les fichiers python.

Ce fichier propose différentes méthodes pour faire des requêtes au fichier ressources.py

1
<!doctype html>
2
<html  lang="fr">
3
    <head>
4
        <meta charset="utf-8">
5
        <meta name="viewport" content="width=device-width, initial-scale=1">
6
        <title>Musiques </title>
7
        <link href="/nsi/components/bootstrap/css/bootstrap.min.css" rel="stylesheet">
8
	    <link rel="stylesheet" type="text/css" href="../css/default.css">
9
	    
10
    </head>
11
<body class="test">
12
    <header>
13
  <!-- Fixed navbar -->
14
  <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
15
    <div class="container-fluid">
16
      <a class="navbar-brand" href="#">Le mini projet JBK: - page de tests </a>
17
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
18
        <span class="navbar-toggler-icon"></span>
19
      </button>
20
      <div class="collapse navbar-collapse" id="navbarCollapse">
21
        <ul class="navbar-nav me-auto mb-2 mb-md-0">
22
          <li class="nav-item">
23
            <a class="nav-link active" aria-current="page" href="../../1nsi.html">Retour accueil</a>
24
          </li>
25
          <li class="nav-item">
26
            <a class="nav-link" href="index.html">Ma page </a>
27
          </li>
28
          <li class="nav-item">
29
            <a class="nav-link disabled">Disabled</a>
30
          </li>
31
        </ul>
32
        <form class="d-flex" role="search">
33
          <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
34
          <button class="btn btn-outline-success" type="submit">Search</button>
35
        </form>
36
      </div>
37
    </div>
38
  </nav>
39
</header>
40
<!--
41
Début du corps de la page
42
-->
43
  <div class="container">
44
    <H1>Les tests  ...</H1>
45
  <div class="row">
46
    <!--Colonne de gauche-->
47
    <div class="col-sm gauche">
48
      <h1> Sous forme d'url (méthode get)</h1>
49
      Afficher les artistes:<br />
50
      <a href="../cgi/ressources.py?afaire=voirArtistes">voir les artistes</a><br />
51
      <!-- toujours sous forme de liens direct, mais le choix est déjà fait-->
52
      Afficher les albums d'aerosmith:<br/>
53
      <a href="../cgi/ressources.py?afaire=voirArtistes&artiste=Aerosmith">voir les albums d'Aerosmith</a><br/>
54
55
      Afficher les morceaux de l'album Arrêt sur images:<br/>
56
57
      <a href="../cgi/ressources.py?afaire=voirAlbums&album=Arrêt+sur+image"> Voir les titres</a>
58
    </div>
59
    <div class="col-sm milieu">
60
      <h1> Formulaires get</h1>
61
      <!--
62
        demande affichage artiste , une seule variable, on lui donne le nom "afaire", inutile d'afficher la variable 
63
      -->
64
      Premier formulaire: afficher les artistes ...<br />
65
      <form action="../cgi/ressources.py" method="get" >
66
          <input type="hidden" name="afaire" value="voirArtistes" >
67
          <input type="submit" class="btn btn-success" value="Voir les artistes">
68
          <!-- changer le type de bouton, voir ici:https://getbootstrap.com/docs/4.0/components/buttons/-->
69
      </form>
70
      <hr />
71
      <!--
72
        demande affichage des albums d'un artiste , deux variables,  "afaire" qui vaut "voirAlbums" et un choix d'artistes en menu déroulant
73
        par la suite ce menu devra être chargé automatiquement avec tous les artistes
74
      -->
75
      Deuxième formulaire : afficher les albums de l'artiste choisi ...<br />
76
      <form action="../cgi/ressources.py" method="get" >
77
        <input type="hidden" name="afaire" value="voirArtistes" >
78
        Choisir l'artiste <br />
79
        <select name="artiste">
80
          <option value="Alice Cooper">Alice cooper </option>
81
          <option value="Aerosmith">Aerosmith</option>
82
83
        </select>
84
        <input type="submit" class="btn btn-success" value="Voir les albums">
85
    </form>
86
    <hr />
87
    <!--
88
      demande affichage des morceaux d'un album, deux variables,  "afaire" qui vaut "voirAlbums" et un choix d'albums en menu déroulant
89
      par la suite ce menu devra être chargé automatiquement avec tous les albums.
90
      On aurait mu palcer en type hidden le nom de l'artiste ... au cas ou 
91
    -->
92
    Troisème formulaire : afficher les albums de l'artiste choisi ...<br />
93
    <form action="../cgi/ressources.py" method="get" >
94
      <input type="hidden" name="afaire" value="voirAlbums" >
95
      
96
      Choisir l'album <br />
97
      
98
        <input type="radio" value="Carnets de bord" name="album">Carnets de bord <br />
99
        <input type="radio" value="Arrêt sur image" name="album">Arrêt sur image <br />
100
        <input type="radio" value="If" name="album">If <br />
101
      <input type="submit" class="btn btn-success" value="Voir les morceux de cet album">
102
  </form>
103
     </div>
104
    <!-- colonne de droite-->
105
    <div class="col-sm droit">
106
     <h1>Formulaires post</h1>
107
     Premier formulaire: afficher les artistes ...<br />
108
     <form action="../cgi/ressources.py" method="post" >
109
      <input type="hidden" name="afaire" value="voirArtistes" >
110
      <input type="submit" class="btn btn-success" value="Voir les artistes">
111
    </form>
112
    <hr />
113
    Deuxième formulaire : afficher les albums de l'artiste choisi ...<br />
114
    <form action="../cgi/ressources.py" method="get" >
115
      <input type="hidden" name="afaire" value="voirArtistes" >
116
      Choisir l'artiste <br />
117
      <select name="artiste">
118
        <option value="Alice Cooper">Alice cooper </option>
119
        <option value="Aerosmith">Aerosmith</option>
120
121
      </select>
122
      <input type="submit" class="btn btn-success" value="Voir les albums">
123
  </form>
124
  <hr />
125
  Troisème formulaire : afficher les albums de l'artiste choisi ...<br />
126
    <form action="../cgi/ressources.py" method="post" >
127
      <input type="hidden" name="afaire" value="voirAlbums" >
128
      
129
      Choisir l'album <br />
130
      
131
        <input type="radio" value="Carnets de bord" name="album">Carnets de bord <br />
132
        <input type="radio" value="Arrêt sur image" name="album">Arrêt sur image <br />
133
        <input type="radio" value="If" name="album">If <br />
134
      <input type="submit" class="btn btn-success" value="Voir les morceux de cet album">
135
  </form>
136
    </div>
137
  </div>
138
</div> 
139
 <!--   
140
<script src="/nsi/components/jquery-3.3.1.min.js"></script>      
141
 <script src="../js/default.js"></script>
142
-->
143
</body>
144
145
</html>

les fichiers python, la bibliothèque fonctions.py et dessous le fichiers ressources.py

1
#!/usr/bin/python3
2
# * coding: UTF8 *
3
4
5
#renvoie Faux si l'artise est dans la liste 
6
def TestDoublons(liste,artiste):
7
    for i in liste:
8
        pass
9
    return False
10
11
12
#Ajoute un artiste à une liste en évitant les doublons 
13
def AjouteA(liste,artiste):
14
	#on teste les doublons
15
    pass
16
    return 
17
18
19
20
#charge les albums d'un artiste 
21
def GetAlbums(artiste,lines):
22
	Albums =[]
23
	for ligne in lines:
24
		pass
25
	return Albums
26
27
28
#charge les morceaux d'un album 
29
def GetMorceaux(album,leficher):
30
	Morceaux =[]
31
	for ligne in lines:
32
		pass
33
	return Morceaux
34
35
36
#Charge les artistes dans une liste nommée LA à partir d'un fichier , puis retounre la liste
37
def loadArtistes(lefichier):
38
    lesmorceaux = fromfiletoliste(lefichier)
39
    LA =[]
40
    for line in lesmorceaux:
41
        tampon = line.split(';')
42
        if not(TestDoublons(LA,tampon[0])):
43
            LA.append(tampon[0])
44
    return LA
45
46
47
#Retourne le fichier passe en argument comme une liste nommée lines
48
def fromfiletoliste(Unfichier):
49
	file = open(Unfichier, "r",encoding="utf8")
50
	lines = file.readlines()
51
	file.close()
52
	return lines
1
#!/usr/bin/python3
2
# * coding: UTF8 *
3
4
5
# -*- coding: UTF-8 -*-
6
import cgitb
7
#https://docs.python.org/2/library/cgi.html
8
import cgi,os,sys
9
10
#pour afficher les erreurs 
11
cgitb.enable()
12
13
#pour l'instant, on affiche du html , mais plus tard ...
14
print ("Content-Type: text/html ;charset=utf-8\r\n\r\n")
15
#on récupère le formulaire ou les données 
16
form = cgi.FieldStorage()
17
18
#On importe notre bibliothèque
19
from fonctions import *
20
21
#notre dictionnaire d'action est pour l'instant vide,  mais il existe !
22
choix = {}
23
24
#en fonction des choix de l'utilisateur, toutes les donnéees ne seront pas disposnible , par précaution on va compléter 
25
#le dictionnaire avec des valeurs "vides"
26
choix["action"]='vide'
27
choix["artiste"]='vide'
28
29
30
#choix.append('action':"vide")
31
32
#en cgi, les données sont passées par un formulaire: méthodes  post ou get , ou directement par une url : méthode get 
33
# #on récupère  les données 
34
form = cgi.FieldStorage()
35
#Les lignes suivantes, permettent de "récupérer " les données éventuellement envoyées 
36
if form.getvalue('action'):
37
    choix['action'] = form['action'].value
38
39
#pour l'intant le fichier ne change pas 
40
choix['fichier']="../data/listeok.csv"
41
42
if form.getvalue('artiste'):
43
    choix['artiste'] = form['artiste'].value
44
45
if form.getvalue('album'):
46
    choix['album'] = form['album'].value
47
48
if form.getvalue('morceau'):
49
    choix['morceau'] = form['morceau'].value
50
51
52
"""
53
if choix['action'] == 'voirArtistes':
54
	lesArtistes = loadArtistes(choix['fichier'])
55
	for i in lesArtistes :
56
		print(i+"<br />")
57
			
58
59
if choix['action'] == 'voirAlbums':
60
	lesAlbums = loadArtistes(choix['fichier'],choix['fichier'])
61
    for i in lesAlbums:
62
        print(i)
63
64
65
if choix['action'] == 'voirMorceaux':
66
	LesAlbums = GetAlbums(choix['album'],choix['fichier'])
67
68
69
if choix['action'] == 'morceaux':
70
	LesMorceaux = GetMorceaux(choix['morceau'],choix['fichier'])
71
72
"""