Écriture de vues

Une fonction de vue, ou vue pour faire simple, est une simple fonction Python acceptant une requête Web et renvoyant une réponse Web. Cette réponse peut contenir le contenu HTML d’une page Web, une redirection, une erreur 404, un document XML, une image… ou vraiment n’importe quoi d’autre. La vue elle-même contient la logique nécessaire pour renvoyer une réponse. Ce code peut se trouver à l’emplacement de votre choix, pour autant qu’il soit dans le chemin Python. Il n’y a pas d’autres exigences, pas de « magie » comme on dit. Mais comme il faut bien mettre ce code quelque part, la convention est de placer les vues dans un fichier nommé views.py se trouvant dans un projet ou un répertoire d’application.

Une vue simple

Voici une vue qui renvoie l’heure et la date actuelle, sous forme d’un document HTML :

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

Passons ce code en revue ligne par ligne :

  • Nous importons d’abord la classe HttpResponse à partir du module django.http, ainsi que la bibliothèque datetime de Python.

  • Puis, nous définissons une fonction nommée current_datetime. C’est la fonction de vue. Chaque fonction de vue accepte un objet HttpRequest comme premier paramètre, typiquement nommé request.

    Remarquez que le nom de la fonction de vue n’a aucune importance ; la vue ne doit pas être nommée d’une certaine manière pour que Django puisse la reconnaître. Nous l’avons appelée current_datetime ici car ce nom indique clairement ce qu’elle fait.

  • La vue renvoie un objet HttpResponse contenant la réponse générée. Chaque fonction de vue est chargée de renvoyer un objet HttpResponse (il y a des exceptions, mais nous les aborderons plus tard).

Le fuseau horaire de Django

Django contient un réglage TIME_ZONE (fuseau horaire) valant par défaut America/Chicago. Vous ne vivez probablement pas à cet endroit, vous allez donc la modifier dans votre fichier de réglages.

Correspondance entre URL et vues

Ainsi, pour résumer, cette fonction de vue renvoie une page HTML contenant la date et l’heure actuelles. Pour afficher cette vue avec une URL particulière, il est nécessaire de créer une configuration d’URL. Voir Distribution des URL pour les instructions.

Renvoi d’erreurs

Le renvoi de codes d’erreur HTTP est simple dans Django. Il existe des sous-classes de HttpResponse pour tous les codes de statut HTTP les plus courants autres que 200 (qui signifie « OK »). La liste complète des sous-classes disponibles se trouve dans la documentation des requêtes/réponses. Il suffit de renvoyer une instance de l’une de ces sous-classes au lieu d’une réponse HttpResponse normale afin de signaler une erreur. Par exemple :

from django.http import HttpResponse, HttpResponseNotFound

def my_view(request):
    # ...
    if foo:
        return HttpResponseNotFound('<h1>Page not found</h1>')
    else:
        return HttpResponse('<h1>Page was found</h1>')

Il n’existe pas de sous-classe spécialisée pour chaque code de réponse HTTP possible, car la plupart ne se rencontrent que très rarement. Cependant, comme décrit dans la documentation de HttpResponse, il est aussi possible de transmettre le code de statut HTTP au constructeur de HttpResponse pour créer une classe à renvoyer pour n’importe quel code de statut. Par exemple :

from django.http import HttpResponse

def my_view(request):
    # ...

    # Return a "created" (201) response code.
    return HttpResponse(status=201)

Comme les erreurs 404 sont de loin les erreurs HTTP les plus fréquentes, il existe une façon simplifiée de les traiter.

L’exception Http404

class django.http.Http404

Lorsque vous renvoyez une erreur telle que HttpResponseNotFound, vous êtes chargé de définir le code HTML de la page d’erreur résultante :

return HttpResponseNotFound('<h1>Page not found</h1>')

Par commodité et parce qu’il est conseillé d’avoir une page d’erreur 404 cohérente pour tout un site, Django fournit une exception Http404. Si vous générez Http404 quelque part dans une fonction de vue, Django l’intercepte et renvoie la page d’erreur standard de l’application, en compagnie du code d’erreur HTTP 404.

Exemple d’utilisation :

from django.http import Http404
from django.shortcuts import render_to_response
from polls.models import Poll

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render_to_response('polls/detail.html', {'poll': p})

Afin d’exploiter l’exception Http404 à son maximum, il est recommandé de créer un gabarit affiché lorsque des erreurs 404 sont générées. Ce gabarit doit s’appeler 404.html et se trouver au premier niveau de l’arborescence des gabarits.

Personnalisation des vues d’erreur

La vue 404 (page non trouvée)

django.views.defaults.page_not_found(request, template_name='404.html')

Lorsque vous générez une exception Http404 à partir d’une vue, Django charge une vue spéciale consacrée au traitement des erreurs 404. Par défaut, il s’agit de la vue django.views.defaults.page_not_found() qui produit soit un message « Non trouvé » très simple, soit charge et affiche le gabarit 404.html si celui-ci existe dans le répertoire racine des gabarits.

La vue 404 par défaut transmet une variable au gabarit : request_path, qui correspond à l’URL qui a produit l’erreur.

La vue page_not_found convient à 99 % des applications Web, mais si vous souhaitez surcharger cette vue, vous pouvez définir handler404 dans votre configuration d’URL racine (la définition de handler404 à tout autre endroit est sans effet), comme ceci :

handler404 = 'mysite.views.my_custom_404_view'

En arrière-plan, Django détermine la vue 404 en cherchant handler404 dans la configuration d’URL racine, et se rabat sur django.views.defaults.page_not_found s’il ne trouve rien.

Trois éléments à signaler à propos des vues 404 :

  • La vue 404 est également appelée si Django ne trouve pas de correspondance après avoir vérifié chaque expression régulière dans la configuration d’URL.

  • La vue 404 reçoit un objet RequestContext et peut accéder aux variables produites par le réglage TEMPLATE_CONTEXT_PROCESSORS (par ex. MEDIA_URL).

  • Si DEBUG est défini à True (dans votre module de réglages), la vue 404 ne sera jamais utilisée, mais elle est remplacée par l’affichage de la configuration d’URL ainsi que de certaines informations de débogage.

La vue 500 (erreur de serveur)

django.views.defaults.server_error(request, template_name='500.html')

De la même façon, Django passe par un comportement d’exception en cas d’erreur d’exécution dans le code d’une vue. Lorsqu’une vue génère une exception, Django appelle par défaut la vue django.views.defaults.server_error, qui produit soit un message « Erreur de serveur » très simple, soit charge et affiche le gabarit 500.html si celui-ci existe au premier niveau du répertoire des gabarits.

La vue 500 par défaut ne transmet aucune variable au gabarit 500.html, celui-ci recevant un context Context vide pour minimiser le risque d’erreurs supplémentaires.

Cette vue server_error convient à 99 % des applications Web, mais si vous souhaitez surcharger cette vue, vous pouvez définir handler500 dans votre configuration d’URL racine, comme ceci :

handler500 = 'mysite.views.my_custom_error_view'

En arrière-plan, Django détermine la vue 500 en cherchant handler500 dans la configuration d’URL racine, et se rabat sur django.views.defaults.server_error s’il ne trouve rien.

Une chose à signaler à propos des vues 500 :

  • Si DEBUG est défini à True (dans votre module de réglages), la vue 500 ne sera jamais utilisée, mais elle est remplacée par l’affichage de la pile d’appels (« traceback ») ainsi que de certaines informations de débogage.

La vue 403 (accès interdit ou « HTTP Forbidden »)

django.views.defaults.permission_denied(request, template_name='403.html')

Dans la même perspective que pour les vues 404 et 500, Django contient une vue pour gérer les erreurs 403 d’accès refusé. Si une vue génère une exception 403, Django appelle par défaut la vue django.views.defaults.permission_denied.

Cette vue charge et affiche le gabarit 403.html se trouvant à la racine du répertoire des gabarits, ou, si ce fichier n’existe pas, affiche le texte « 403 Forbidden » comme le prescrit le RFC 2616 (la spécification HTTP 1.1).

django.views.defaults.permission_denied est provoquée par une exception PermissionDenied. Pour refuser l’accès à l’une de vos vues, voici le code pouvant être utilisé :

from django.core.exceptions import PermissionDenied

def edit(request, pk):
    if not request.user.is_staff:
        raise PermissionDenied
    # ...

Il est possible de surcharger django.views.defaults.permission_denied de la même manière qu’on peut le faire pour les vues 404 et 500 en définissant handler403 dans la configuration d’URL racine :

handler403 = 'mysite.views.my_custom_permission_denied_view'

La vue 400 (mauvaise requête)

New in Django 1.6.
django.views.defaults.bad_request(request, template_name='400.html')

Lorsqu’une exception SuspiciousOperation est générée dans Django, elle peut être traitée par un composant de Django (par exemple en réinitialisant les données de session). Lorsque ce n’est pas le cas, Django considère que la requête actuelle est une « mauvaise requête », au lieu de produire une erreur de serveur.

django.views.defaults.bad_request est globalement très semblable à la vue server_error, mais renvoie un code de statut 400 indiquant que la condition d’erreur est le résultat d’une opération du client.

Comme server_error, la vue par défaut bad_request convient à 99 % des applications Web, mais si vous souhaitez surcharger cette vue, vous pouvez définir handler400 dans votre configuration d’URL racine, comme ceci :

handler400 = 'mysite.views.my_custom_bad_request_view'

Les vues bad_request ne sont également utilisées que lorsque DEBUG vaut False.