title: Rédaction de votre première appli Django, partie 4 : Conception d'un formulaire et vues génériques slug: redaction-de-votre-premiere-appli-django-partie-4-conception-d-un-formulaire-et-vues-generiques date: 2006-06-17 19:50:21 type: post vignette: images/logos/django.png contextual_title1: Le langage de template Django : Pour les auteurs de templates contextual_url1: 20060815-le-langage-de-template-django-pour-les-auteurs-de-templates contextual_title2: Comparaison de TurboGears et Django, deux frameworks web Python contextual_url2: 20060715-comparaison-de-turbogears-et-django-deux-frameworks-web-python contextual_title3: Rédaction de votre première appli Django, partie 3 : Création des vues de l'interface publique contextual_url3: 20060617-redaction-de-votre-premiere-appli-django-partie-3-creation-des-vues-de-l-interface-publique

Ce tutoriel commence là où le Tutoriel 3 s'est achevé. Nous continuons notre application de sondage en ligne et allons nous intéresser à la génération d'un formulaire simple et au ré-arrangement de notre code.

Générer un formulaire simple

Commençons par mettre à jour notre template de détail de sondage issu du dernier tutoriel de façon à ce que le template contienne un élement HTML <form>:

<h1>{{ poll.question }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}


<form action="/polls/{{ poll.id }}/vote/" method="post">
{% for choice in poll.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />

    <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
{% endfor %}
<input type="submit" value="Voter" />
</form>

Un bref rappel :

À présent, créons une vue Django qui récupère les données soumises et fait quelque chose avec. Rappelez-vous, dans le Tutoriel 3, nous avons créé une URLconf pour l'application de sondage qui incluait cette ligne:

(r'^(?P<poll_id>\d+)/vote/$', 'monsite.polls.views.vote'),

Donc créons une fonction vote() dans monsite/polls/views.py:

from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect
from monsite.polls.models import Choice, Poll
# ...
def vote(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    try:
        selected_choice = p.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Réaffiche le formulaire de vote.
        return render_to_response('polls/detail.html', {
            'poll': p,
            'error_message': "Vous n'avez pas sélectionné de choix.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # Retourne toujours un HttpResponseRedirect après validation
        # des données POST. Ceci empèche que les données soient postées
        # deux fois si l'utilisateur clique sur le bouton Précédent.
        return HttpResponseRedirect('/polls/%s/results/' % p.id)

Ce code inclus des parties que nous n'avons pas encore étudiées dans ce tutoriel :

Comme il est mentionné dans le Tutoriel 3, request est un objet HTTPRequest. Pour en savoir plus au sujet des objets HTTPRequest, lisez la documentation sur les requêtes et réponses.

Après qu'un vote ait été effectué dans un sondage, la vue vote() redirige vers la page de résultats du sondage. Écrivons cette vue:

def results(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/results.html', {'poll': p})

C'est presque la même que la vue detail() du Tutoriel 3. La seule différence est le nom du template. Nous nous occuperons de la redondance plus tard.

Maintenant, créons un template results.html:

<h1>{{ poll.question }}</h1>

<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>

À présent, rendez vous à l'adresse /polls/1/ dans votre navigateur et soumettez un vote. Vous devriez voir une page de résultats qui est mise à jour à chacun de vos votes. Si vous soumettez le formulaire sans avoir spécifié de choix, vous devriez observer le message d'erreur.

Utilisez les vues génériques : Moins il y a de code mieux c'est

Les vues detail() (du Tutoriel 3) et results() sont ridiculeusement simples -- et, comme nous l'avons signalé plus haut, redondantes. La vue index() (du Tutoriel 3 aussi), qui affiche une liste de sondages, est similaire.

Ces vues correspondent à des cas courants de développement Web basic : récupérer des données de la base de données en fonction d'un paramètre passé dans l'URL, charger un template et retourner le template complété. Comme c'est si courant, Django dispose d'un raccourci, baptisé le système des « vues génériques ».

Les vues génériques fournissent une couche d'abstraction tellement importante que vous n'avez même pas besoin de rédiger du code Python pour écrire votre appli.

Convertissons notre application de sondage en utilisant le système des vues génériques, nous allons ainsi pouvoir supprimer une bonne partie du code que nous avons écrit précédemment. Il suffit de quelques étapes pour réaliser la conversion.

Pourquoi ce ré-arrangement du code ?

Géneralement, quand vous allez écrire une application Django, vous allez évaluer si les vues génériques sont une bonne solution à votre problème, et vous allez les utiliser dès le début sans avoir à refactoriser votre code en plein développement. Mais ce tutoriel s'est intentionnellement focalisé sur l'écriture de vues « de manière hardue » jusqu'à présent, de façon à ce que vous preniez conscience des concepts généraux.

Premièrement, éditez votre fichier d'URLconf polls/urls.py. Il devrait ressembler à ça, d'après les tutoriaux précédents:

from django.conf.urls.defaults import *

urlpatterns = patterns('monsite.polls.views',
    (r'^$', 'index'),
    (r'^(?P<poll_id>\d+)/$', 'detail'),
    (r'^(?P<poll_id>\d+)/results/$', 'results'),
    (r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

Faites le ressembler à:

from django.conf.urls.defaults import *
from monsite.polls.models import Poll

info_dict = {
    'queryset': Poll.objects.all(),
}

urlpatterns = patterns('',
    (r'^$', 'django.views.generic.list_detail.object_list', info_dict),
    (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
    (r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html')),
    (r'^(?P<poll_id>\d+)/vote/$', 'monsite.polls.views.vote'),
)

Nous utilisons ici deux vues génériques : object_list et object_detail. Respectivement, ces deux vues rendent abstraits les concepts « d'affichage d'une liste d'objets » et « d'affichage d'une page de détails pour un type particulier d'objet ».

Par défaut, la vue générique object_detail utilise un template appelé <nom_appli>/<nom_module>_detail.html. Dans notre cas, ce sera le template appelé "polls/poll_detail.html". Donc, renommons polls/detail.html en polls/poll_detail.html, et changeons la ligne render_to_response() en vote().

De façon similaire, la vue générique object_list utilise un template appelé <nom_appli>/<nom_module>_list.html. Donc, renommons polls/index.html en polls/poll_list.html.

Puisque nous avons plus d'une entrée dans l'URLconf qui utilisent object_detail pour l'application de sondage, nous spécifions manuellement un nom de template pour la vue des résultats : template_name='polls/results.html'. Sinon, les deux vues auraient utilisé le même template. Notez l'utilisation de dict() pour retourner un dictionnaire modifié à la place.

Dans les tutoriels précédents, les templates sont utilisés dans un contexte contenant les variables poll et latest_poll_list. Ici, les vues génériques nécessitent d'avoir les variables contextuelles object et object_list. Éditez vos templates et modifiez chaque référence à latest_poll_list par object_list, et chaque référence à poll par object.

Vous pouvez maintenant supprimer les vues index(), detail() et results() de polls/views.py. Nous n'en avons plus besoin -- elles ont été remplacées par les vues génériques.

La vue vote() est toujours requise. Néanmoins, elle doit être modifiée pour être utilisée dans les nouveaux templates et les nouvelles variables contextuelles. Changez l'appel au template polls/detail.html par polls/poll_detail.html, et passez object dans le contexte au lieu de poll.

Lancez le serveur et utilisez votre nouvelle appli de sondage avec les vues génériques.

Pour davantage de détails quant aux vues génériques, lisez la documentation sur les vues génériques.

À venir

Les tutoriels s'arrêtent ici pour le moment. Mais revenez prochainement pour la suite des réjouissances :

Vous pouvez maintenant retourner à la page d'accueil des traductions de la documentation de Django.

Cette traduction correspond à la révision 3589 (post 0.95).