Ce module définies les actions possibles sur notre serveur ainsi qu'une action par défaut. Il pourra être complété quand nous disposerons d'une base de données fonctionnelle.
Ce module nécessite les modules filemanager, html et template.
'''
fichier routesdefinition.py
Définition des routes
'''
from filemanager import FileManager
from html import Html
from template import Template
def get_routes(bdd):
routes = []
# route pour le chargement de fichier image ou autre
def load_file(req, params):
fm = FileManager(req.url())
if fm.exists_in_public():
return fm.load_binary_in_public()
error_page = Html(error_code = 404)
return error_page.encode()
routes.append({'pattern':'<filename>.(?:jpg|jpeg|png|ico|css|js|bmp)', 'action':load_file})
# route pour le chargement de fichier html
def load_html(req, params):
html = Html(filename = req.url())
return html.encode()
routes.append({'pattern':'<filename>.html', 'action':load_html})
# chargement du template exemple
def load_template_exemple(req, params):
tpl = Template('exemple')
html = Html(content = tpl.render(params))
return html.encode()
routes.append({'pattern':'/exemple-titre=<titre>-numero=<numero>', 'action':load_template_exemple})
return routes
def default_action(req):
html = Html(filename = 'index.html')
return html.encode()
On peut définir une fonction à l'intérieur d'une fonction ! Par exemple def load_file revient à créer une variable load_file contenant une fonction. Cette variable étant définie à l'intérieur de get_routes, ce n'est pas une variable globale visible de partout. C'est une technique permettant de définir des fonctions tout en masquant les références à ces fonctions. L'idée est compliquée, je n'insiste pas pour l'instant.
La première des routes définies sert à répondre à une demande de chargement de fichier : fichier image, fichier css…
Le schéma '<filename>.(?:jpg|jpeg|png|ico|css|js|bmp)' permet de détecter que l'on demande un fichier dont l'extension est dans la liste. Si on demandait un fichier *.gif qui n'est pas dans la liste, cette route ne serait pas déclenchée.
Lorsque le schéma est vérifié, le routeur déclenche l'action correspondante, c'est à dire la fonction load_file, ligne 14.
def load_file(req, params):
fm = FileManager(req.url())
if fm.exists_in_public():
return fm.load_binary_in_public()
error_page = Html(error_code = 404)
return error_page.encode()
FileManager pour tenter d'ouvrir le fichier demandé,Les routes déjà créées suffisent dans un premier temps. Les routes suivantes seront développées après les modules – requete, filemanager, routeur, template, listtemplate, html – c'est à dire quand on développera le module bdd.
Demande d'affichage de la liste de tous les livres. On choisit une URL pour cette requête : http://mon-domaine/show-livres. Le schéma est donc simplement "show-livres"
Dans notre cas, mon-domaine est localhost. Lors de la détection de la requête par le serveur, la partie domaine est absente, il ne reste donc que /show-livres.
Cette route déclenchera l'exécution de la fonction show_livres :
def show_livres(req, params):
data = bdd.getLivres()
tpl = ListTemplate('show-livres')
content_livres = tpl.render({}, data)
page = Html(content = content_livres)
return page.encode()
Il faut donc créer la méthode BDD.get_livres(self) qui envoie la requête
SELECT idLivre, titre, idAuteur, idEditeur FROM livres
La fonction devra renvoyer une liste de forme :
[
{"idLivre":1, "titre":"Je suis en CE2 : Le nouveau look de Suzy", "idAuteur":1, "idEditeur":1},
{"idLivre":2, "titre":"Je suis en CP : La médaille d'or", "idAuteur":1, "idEditeur":1},
...
]
Il s'agit d'une première approche. Il pourrait être intéressant de complexifier la requête afin d'obtenir le nom de l'auteur en plus de son identifiant.
On pourra adopter un tableau.
<!-- template show-livres.head.tpl --> <table> <tr><th>id</th><th>titre</th><th>auteur</th><th>éditeur</th></tr>
<!-- template show-livres.item.tpl -->
<tr><td>{idLivre}</td><td>{titre}</td><td>{idAuteur}</td><td>{idEditeur}</td></tr>
<!-- template show-livres.foot.tpl --> </table>
Nous affichons l'identifiant de l'auteur et de l'éditeur ce qui pour l'utilisateur n'a pas grand intérêt. Il faudrait complexifier la requête BDD de façon à obtenir le nom de l'éditeur et le nom de l'auteur afin de pouvoir l'afficher.
Le template précédent ne suffit pas. En effet, il ne donne que le tableau. Mais une page html complète contient une partie <head>, on peut imaginer qu'il y a un menu présent identique sur toutes les pages…
On propose donc de créer un template de base valable pour toutes les pages et qui prévoit un emplacement pour y placer le contenu spécifique de la page en cours.
<!-- template base.tpl -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title>{titre}</title>
<link href="./styles.css" media="screen" rel="stylesheet" type="text/css" />
<link rel="icon" href="livres.png" />
</head>
<body>
<div class="head">
Ceci est l'entête, c'est le bon endroit pour mettre un menu !
</div>
{contenu}
<div class="foot">
Ceci est le pied de page, ce serait bien qu'il soit identique sur toutes les pages.
</div>
</body>
</html>
Pour compléter ce template, il faut lui fournir un titre et un contenu. Il faut modifier la fonction show_livres :
def show_livres(req, params):
data = bdd.getLivres()
tpl = ListTemplate('show-livres')
content_livres = tpl.render({}, data)
tpl_base = Template('base')
content_html = tpl_base.render({
'titre':'Liste des livres',
'contenu':content_livres
})
page = Html(content = content_html)
return page.encode()
Le travail est exactement le même pour produire la liste des auteurs et la liste des éditeurs. Quand on a compris le principe, la conception d'un tel site web devient vite assez répétitive. Heureusement, il existe des outils permettant d'accélérer le travail.
On choisit une URL qui permet d'indiquer l'identifiant du livre désiré. On choisit le schéma : "show-livre:<id>". Ainsi quand on écrira http://localhost/show-livre:69 dans l'URL, le serveur détectera qu'il s'agit de cette route et que la valeur de id est de 69.
Une fois cette détection faite, le routeur déclenche l'action correspondante.
L'action prend la forme d'une fonction, par exemple show_livre(req, params). params est un dictionnaire qui ici contiendra {'id':69}.
def show_livre(req, params):
id = int(params['id'])
data = bdd.get_livre(id)
if data == None:
page = Html(error_code = 404)
return page.encode()
tpl = Template('show-livre')
content_livre = tpl.render(data)
tpl_base = Template('base')
content_html = tpl_base.render({
'titre':data['titre'],
'contenu':content_livre
})
page = Html(content = content_html)
return page.encode()
id soit de type int,show_livres : ligne 4, on envisage le cas de la demande d'un livre inexistant. Dans ce cas, on renvoie une page d'erreur 404.
Il faut donc créer la méthode BDD.get_livre(self, id:int).
À vous de déterminer la requête nécessaire. Cette fonction devrait renvoyer un dictionnaire – exemple pour le livre d'id 69 :
{
"idLivre":69,
"titre":"Journal d'un dégonflé : La vérité toute moche",
"idAuteur":10,
"nomAuteur":"Jeff Kinney",
"idEditeur":7,
"nomEditeur":"Seuil",
"disponible":"Oui"
}
La dernière info est la plus difficile. Vous pouvez la laisser de côté dans un premier temps.
<!-- template show-livre.tpl -->
<h1>{titre}</h1}
<p><b>Auteur :</b> {nomAuteur}</p>
<p><b>Éditeur :</b> {nomEditeur}</p>
<p><b>Disponible ?</b> {disponible}</p>
Supposez que l'on ai affiché la liste des livres. On aimerait qu'un simple clic sur le titre d'un livre permette d'afficher la page concernant ce livre.
On sait que pour afficher le livre d'id 69, il faut entrer l'URL show-livre:69. Le chargement se fait donc par l'URL et donc il sera naturel d'utiliser un lien hypertexte avec une balise <a>.
Revenons au template pour les items de show_livres. On fait la modification :
<!-- template show-livres.item.tpl -->
<tr><td>{idLivre}</td><td><a href="/show-livre:{id}">{titre}</a></td><td>{idAuteur}</td><td>{idEditeur}</td></tr>
Notez l'ajout de la balise <a> dotée d'un lien href="/show-livre:{id}". Cliquer sur ce lien change l'URL et provoque l'affichage de la page correspondante.
Si vous arrivez à créer une page pour l'affichage d'un auteur, vous n'aurez aucune peine à créer un lien pour visualiser l'auteur. Un grand intérêt des documents hypertexte est cette facilité du passage d'un élément à l'autre.
Si nous en avons le temps, nous envisagerons l'ajout d'une requête de type POST.
Une telle requête n'est pas difficile en principe mais elle requiert un travail fastidieux :