Dans le cadre du projet SQL, nous avons vu que l'application pouvait prendre des proportions telles que le mélange entre ce qui relevait de texte affichés, et le fonctionnement de l'appli, devenait problématique.
Je vais vous donner ici un guide d'une démarche possible pour séparer les choses.
Notez que le choix de faire une interface en mode texte est avantageux dans le sens où on se limite à des print et des input. D'un autre côté, quand on dispose d'une interface plus complexe, comme une page web, on a accès à des outils qui font déjà une partie du travail. Je pense par exemple au Combos, c'est bouton permettant de choisir dans une liste.
Pour mes exemples, je poursuis avec l'exemple de la base de données avec films et artistes.
C'est la première question à se poser.
Tout ces éléments peuvent se mélanger. Par exemple, si j'affiche un artiste, je peux prévoir de faire suivre la fiche artiste d'un menu me permettant d'afficher tel films auquel il a participé.
Il y a aussi des comportements à prévoir.
On ne pourra pas éviter de produire tout un tas d'items, objets, fonctions qui se ressemblent. La structure utilisée pour créer un film va ressembler à celle permettant d'ajouter un artiste. On peut réfléchir beaucoup pour ne pas écrire deux fois la même chose, mais il y aura toujours des petites particularités que l'un a mais pas l'autre et qui rendront la tâche difficile.
Pour rendre le code plus simple et mieux organisé, on essaie d'organiser chaque partie du programme indépendamment des autres. Nous allons créer un module rien que pour le cas artiste. Ce module pourra gérer l'ajout d'un artiste et l'affichage d'une fiche artiste.
Le module artiste ne doit pas dépendre des modules concernant les films par exemple.
#module artiste
import sql
def add():
"""ajout d'un artiste dans la base"""
print("Ajouter un artiste.")
nom = input("Donnez son nom :")
prenom = input("Donnez son prénom :")
naissance = input("Donnez sa date de naissance :")
bio = input("Donnez sa biographie :")
sql.insert_artiste(prenom, nom, naissance, bio)
def display(id:int):
"""affichage de l'artiste d'identifiant id"""
# pas fait
# pourrait afficher la liste des films auxquels l'artiste a participé
pass
Quelques remarques :
<input>.insert_artiste dans le module sql.
#module artiste
def add(db):
"""db: objet SQL
ajout d'un artiste dans la base
"""
print("Ajouter un artiste.")
nom = input("Donnez son nom :")
prenom = input("Donnez son prénom :")
naissance = input("Donnez sa date de naissance :")
bio = input("Donnez sa biographie :")
db.insert_artiste(prenom, nom, naissance, bio)
def display(db, id:int):
pass
Mais il manque encore un élément : Que fait-on après, une fois que l'insertion a réussi ? On veut peut-être afficher le contenu de l'artiste que l'on vient de créer. Mais la fonction n'est pas encore créée… Et dans la fonction display, si on affiche les films de l'artiste, il faudrait appeler un module concernant les films… Mais on ne veut pas que les modules soient inter-dépendants.
La solution à ce problème consiste à utiliser un module de routage.
Le routeur sera le chef d'orchestre. Il importera tous les modules correspondant aux morceaux de l'application et il sera chargé de les lancés les uns après les autres.
Le routeur fonctionne travaille sur un identifiant, par exemple une chaîne de texte qui lui dit quoi faire. Par exemple, on convient que
"start" lui demande d'afficher le menu principal,"fin" lui demande d'arrêter,"artiste:add" lui demande d'afficher l'ajout d'artiste.Chaque fois qu'il lance un module, le routeur attend la réponse qui prend la forme d'un nouvel identifiant lui permettant de poursuivre.
Le mieux est encore de poursuivre l'exemple.
Pour la suite, je suppose que l'on a une classe SQL
# main import sql import routeur db = SQL() routeur.start(db, "start") db.close()
# module principal
# j'ajoute un menu principal très simple pour faciliter la compréhension du reste
def display():
print("1. Ajouter artiste")
print("2. Autre chose")
print("3. fin")
def choice():
c = input("Entrez votre choix :")
if c == '1':
return "artiste:add" # notez l'identifiant renvoyé
if c == '3':
return "fin"
#module artiste
def add(db):
"""db: objet SQL
ajout d'un artiste dans la base
"""
print("Ajouter un artiste.")
nom = input("Donnez son nom :")
prenom = input("Donnez son prénom :")
naissance = input("Donnez sa date de naissance :")
bio = input("Donnez sa biographie :")
id = db.insert_artiste(prenom, nom, naissance, bio)
return f"artiste:show:{id}" # notez l'identifiant renvoyé
def show(db, id:int):
pass
# module routeur
import principal
import artiste
def start(db, identifiant:str):
"""
db: objet SQL
identifiant: identifiant du menu à afficher en premier
"""
while identifiant != "fin":
if identifiant == "start":
principal.display()
identifiant = principal.choix()
elif identifiant == "artiste:add":
identifiant = artiste.add(db)
else:
print("identifiant inconnu !")
identifiant = "start"
Que se passe-t-il ?
main crée la connexion SQL et démarre le routeur en lui passant l'objet db et l'identifiant "start.start. Il lance aussitôt la boucle.principal, ce qui provoque l'affichage de ce menu, puis exécute la fonction choice qui consiste à attendre le choix utilisateur.choice, en fonction du numéro entré par l'utilisateur, renvoie un identifiant. Supposons que l'utilisateur a entré 1, l'identifiant renvoyé est donc "artiste:add"."artiste:add"add du module artiste.'id du nouvel item. Disons que cet id est 45.add de artiste renvoie donc "artiste:show:45"identifiant devient donc égal à "artiste:show:45"else ligne 17 qui est validé et identifiant repasse à "start", retour au menu principal."fin", dans routeur, identifiant devient égal à "fin" et la boucle s'arrête.routeur.start se terminant, on revient dans main qui ferme la connexion SQL.artiste.add se contente de renvoyer un identifiant. Elle n'a pas à connaître les modules qui feront le nécessaire. Seul routeur a besoin de connaître tous les modules.show de artiste permettant d'afficher un artiste et alors on peut ajouter dans routeur la route qui mène à cette fonction, c'est à dire qu'on ajoute un test permettant de reconnaître "artiste:show:45“ et déclencher l'affichage.
Vous avez dû voir que l'identifiant dans ce cas est différent : "artiste:show:45"
Dans routeur, on ne va pas créer un test pour tous les id possibles : "artiste:show:1", "artiste:show:2", "artiste:show:3", …
On doit donc être capable de reconnaître que "artiste:show:45" commence par "artiste:show" puis extraire la valeur 45. Il s'agit d'une simple fonction de gestion de texte.
cela donnerait quelque chose comme :
# module routeur
import principal
import artiste
def start(db, identifiant:str):
"""
db: objet SQL
identifiant: identifiant du menu à afficher en premier
"""
while identifiant != "fin":
if identifiant == "start":
principal.display()
identifiant = menu_principal.choix()
elif identifiant == "artiste:add":
identifiant = artiste.add(db)
elif identifiant commence par "artiste:affiche":
id = extraire id de identifiant
identifiant = artiste.show(db, id)
else:
print("identifiant inconnu !")
identifiant = "start"
Ce serait préférable mais ce serait trop compliqué ici. Je vous donne pour information l'idée générale.
Le principe est d'utiliser un fichier texte qui contient l'affichage voulu. Dans le cas d'un site web, il peut s'agir de toute une page html ce qui donne beaucoup de possibilités. Dans le cas d'une page html on pourra d'ailleurs inclure les questions sous forme d'input divers. Avec notre mode texte nous sommes plus limités.
Par exemple on aurait un fichier pour le menu principal :
1. Ajouter artiste 2. Autre chose 3. fin Entrez votre choix
Le module de menu principal n'aurait qu'à ouvrir ce fichier et en afficher le contenu. Ainsi le texte du menu serait séparé et on pourrait en confier la rédaction à quelqu'un qui ne maîtrise pas la programmation.
Pour l'ajout d'un artiste, on pourrait imaginer quelque chose comme
nom = Donnez son nom : prenom = Donnez son prénom : naissance = Donnez sa date de naissance : bio = Donnez sa biographie :
Et le programme Python devrait charger le texte et l'analyser pour repérer les = et transformer ces lignes en une série de input.
Enfin pour l'affichage d'une fiche, on pourrait utiliser un fichier comme :
Fiche de {prenom} {nom}
Né(e) le {naissance}
biographie : {bio}
Et le programme Python devrait charger ce texte et boucher les champ avec les valeurs voulues.