• 20 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 12/12/19

Configurez un champ de recherche et une page 404

Log in or subscribe for free to enjoy all this course has to offer!

Dans le chapitre précédent nous sommes entrés dans le détail des gabarits en ajoutant une structure conditionnelle et un filtre. Allons plus loin en ajoutant une page qui s'affiche en cas d'erreur !

Ajouter des pages d'erreur 404 et 500

Actuellement, lorsqu'une erreur surgit dans le programme une page très utile s'affiche :

Elle apparaît car vous avez indiqué, dans settings.py, que l'application était en mode debug :

disquaire_project/settings.py

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

Très utile, il est néanmoins hautement recommandé de ne pas activer le mode debug en production pour plusieurs raisons. Tout d'abord, votre utilisateur n'a pas vraiment envie de visualiser une page remplie de charabia technique à usage des développeurs. Il cherche un CD, pas un casse-tête. Vous risquez de le faire fuir !

Le second souci est lié à la sécurité : vous exposez des informations sur la structure de l'application, vous donnez donc toutes les astuces pour vous pirater ! C'est un peu comme si vous laissiez la porte de votre maison grande ouverte et que vous écriviez sur une pancarte : "Voleur, sers-toi !".

Etant donné que vous serez amené à désactiver le mode debug, il est important de travailler sur la page que l'utilisateur verra en cas d'erreur.

Remplacez True par False et ajoutez 127.0.0.1 dans la liste des hôtes autorisés :

settings.py

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']

Ajoutez également une erreur dans une de vos vues pour déclencher une erreur :

views.py

def detail(request, album_id):
...
hellfest

Puis relancez le serveur.

Oh, la belle erreur 500 !

Rappel sur les codes de status (status code)

Une requête HTTP envoyée à un serveur fait l'objet d'une réponse de la part de ce dernier, nous en avons déjà parlé. Ces réponses sont organisées sous forme de catégories représentées par des codes. Cela permet de différencier les réponses positives des erreurs !

Catégorie

Description

1xx : les informations

"Je suis en train de traiter votre demande. Voici où elle en est !"

2xx : les succès

"J'ai trouvé ce que vous cherchiez ! Les éléments sont en pièce-jointe."

3xx : les redirections

"Mince, l'élément demandé a été déplacé ailleurs. Je vous redirige vers la bonne adresse."

4xx : les erreurs client

"Je n'ai pas compris ce que vous me demandiez. Pouvez-vous reformuler votre requête ?"

5xx : les erreurs serveur

"Une erreur s'est produite. Quelqu'un a peut-être renversé son café sur mes circuits ou a oublié de m'alimenter. Quoi qu'il en soit, je ne suis pas en état de répondre à votre demande."

La page actuelle étant affreusement anti-productive, je vous propose de créer un gabarit spécifique aux erreurs 500.

Ajouter des gabarits correspondant aux erreurs

Bonne nouvelle : vous n'avez pas besoin d'ajouter une nouvelle vue ! Django cherche automatiquement dans les gabarits disponibles ceux qui portent le nom suivant : 400.html403.html404.html et 500.html. Lisez le code source de Django pour en comprendre le fonctionnement.

Ajoutez donc le gabarit 500.html dans le dossier templates de l'application :

500.html

{% extends 'store/base.html' %}
{% block content %}
<p><em>Oops ! I did it again.</em></p>
<p>Une erreur s'est produite. Nous sommes actuellement en liaison directe avec Britney pour investiguer sur les causes du drame.</p>
<div class="embed-responsive embed-responsive-16by9">
<iframe src="https://www.youtube.com/embed/CduA0TULnow" frameborder="0" allowfullscreen></iframe>
</div>
{% endblock %}

Relancez le serveur. La nouvelle page 500 apparaît sous vos yeux ébahis !

A présent intéressons-nous à l'erreur 404.

Renvoyer une erreur 404 si un item n'est pas trouvé

Une erreur 404 indique qu'un élément demandé n'a pas été trouvé. Nous pouvons l'utiliser pour améliorer la vue detail. En effet, que se passe-t-il si un album n'est pas trouvé ? Une erreur 500 sera renvoyée (erreur serveur).

System check identified no issues (0 silenced).
August 10, 2017 - 17:31:32
Django version 1.11.4, using settings 'disquaire_project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[10/Aug/2017 17:31:35] "GET /store/5032/ HTTP/1.1" 500 3433

Or l'erreur 500 ne reflète pas l'erreur : le serveur ne trouve pas l'album demandé, tout simplement. Il ne s'agit donc pas d'une erreur serveur (code 500) mais d'une ressource non trouvée (code 404).

La méthode get_object_or_404() permet justement de renvoyer une erreur 404 si la ressource n'est pas trouvée !

Remplacez donc la ligne album = Album.objects.get(pk=album_id) par le code suivant :

views.py

from django.shortcuts import render, get_object_or_404
...
def detail(request, album_id):
album = get_object_or_404(Album, pk=album_id)
...

Si vous demandez de nouveau l'album dont l'identifiant est égal à 5032, voici la réponse du serveur :

[10/Aug/2017 17:39:49] "GET /store/5032/ HTTP/1.1" 404 85

Nous avons bien une erreur 404 !

Créez un nouveau gabarit spécifiquement pour l'erreur 404.

templates/404.html

{% extends 'store/base.html' %}
{% block content %}
<p><em>I'm lost. I'm like a king without a throne.</em></p>
<p>L'album que vous demandez est parti écouter Sarah Vaughan à la suite d'une rupture sentimentale.</p>
<p>Nous partons à l'instant même le secourir !</p>
<div class="embed-responsive embed-responsive-16by9">
<iframe src="https://www.youtube.com/embed/E9Rl1GvTsiA" frameborder="0" allowfullscreen></iframe>
</div>
{% endblock %}

Tout fonctionne comme prévu ! Il est temps de passer à l'étape suivante : l'ajout d'un champ de recherche !

Ajouter un champ de recherche

Souvent, nous imaginons que la recherche sur un site est un sujet extrêmement compliqué. Il faut certainement s'y connaître en algorithmique ! Loin s'en faut ! Bien sûr, vous n'allez pas sortir une version concurrente de Google tout de suite... Mais implémenter une recherche basique est désormais chose assez simple, surtout lorsque vous utilisez Django.

D'ailleurs, la recherche est déjà effective sur votre application ! Vous l'avez ajoutée dans les chapitres précédents. Pour rappel, en voici le code :

views.py

def search(request):
query = request.GET.get('query')
if not query:
albums = Album.objects.all()
else:
albums = Album.objects.filter(title__icontains=query)
if not albums.exists():
albums = Album.objects.filter(artists__name__icontains=query)
title = "Résultats pour la requête %s"%query
context = {
'albums': albums,
'title': title
}
return render(request, 'store/search.html', context)

L'algorithme commence par chercher les albums dont le titre correspond à la requête. Si aucune correspondance n'est trouvée, il effectue de nouveau une recherche dans le nom des artistes.

Afin de tester ce processus, vous avez jusqu'à maintenant entré une requête dans l'URL. Par exemple : http://127.0.0.1:8000/store/search/?query=Lulu.

Ajoutez à présent le formulaire qui vous permettra de ne plus passer par l'URL. Qu'est-ce qu'un formulaire ? Il s'agit d'une balise HTML form qui permet de récupérer des informations saisies par l'utilisateur. Les balises contenues à l'intérieur peuvent être de type différent, en fonction des données à recueillir.

<form action="/" method="post">
<input>
</form>

Par défaut, le type d'une balise input est text. Cette balise s'affiche donc sous la forme suivante :

La méthode HTTP POST est utilisée lorsque le formulaire modifie des ressources. Or, dans le cas d'une recherche, rien n'est modifié. Il s'agit plutôt d'une récupération de contenu. Vous pouvez par conséquent utiliser la méthode GET.

Ajoutez un nouveau gabarit, search_form.html, dans lequel vous écrirez un formulaire de recherche. La route de l'action est celle liée à la vue search. Le formulaire ne contient qu'un seul champ input. Quant aux styles, le thème utilisé se base sur Bootstrap. Consultez donc la documentation.

search_form.html

<div class="col-lg-12 detail-separator">
<form class="col-md-6 col-md-offset-3 text-center" action="{% url 'store:search' %}" method="get" accept-charset="utf-8">
<div class="form-group">
<label for="searchForm">Chercher un disque</label>
<input id="searchForm" class="form-control">
</div>
<span class="help-block" id="helpBlock">Trouvez le CD de vos rêves en tapant son titre ou le nom d'un des artistes.</span>
</form>
</div>

Mettez à jour le gabarit list.html pour l'intégrer après le titre et avant la liste des albums :

list.html

<div class="col-lg-12">
<hr>
<h2 class="intro-text text-center">{{ list_title }}
</h2>
<hr class="detail-separator">
</div>
{% include 'store/search_form.html' %} <!-- NEW -->
{% if albums|length_is:"0" %}
...

Et voilà le résultat !

Entrez une valeur dans le champ et appuyez sur "entrée". Aucun résultat n'est trouvé ! :( Pas exactement... Le serveur indique qu'aucun paramètre query n'est présent dans l'URL. En effet, cette dernière est de la forme suivante :

http://127.0.0.1:8000/store/search/?

Pourquoi ? Car j'ai délibérément omis d'ajouter un attribut essentiel à la balise input : name ! La valeur de cet attribut sert à générer l'URL. Par exemple, disons que le nom est lollapalooza :

search_form.html

...
<input id="searchForm" class="form-control" name="lollapalooza">
...

J'entre la requête "La Femme" :

L'URL générée est la suivante :

http://127.0.0.1:8000/store/search/?lollapalooza=La+Femme

Changez le nom par query car c'est celui que vous avez indiqué dans la vue search et cherchez un CD. Tout fonctionne !

404.html

{% extends 'store/base.html' %}
{% block content %}
<p><em>I'm lost. I'm like a king without a throne.</em></p>
<p>L'album que vous demandez est parti écouter Sarah Vaughan à la suite d'une rupture sentimentale.</p>
<p>Nous partons à l'instant même le secourir !</p>
{% include 'store/search_form.html' %}
<iframe src="https://www.youtube.com/embed/E9Rl1GvTsiA" frameborder="0" allowfullscreen></iframe>
{% endblock %}

Dans le prochain chapitre nous nous intéressons à la page listant tous les albums. Vous apprendrez à afficher une liste de résultats sur plusieurs pages grâce à la pagination ! A tout de suite !

Code du chapitre

Retrouvez l'intégralité du code sur ce dépôt GitHub.

Example of certificate of achievement
Example of certificate of achievement