Django : créer un formulaire

Toutes les applications web disposent de tout un tas de formulaires. Ici on va voir comment Django vous aide à gagner du temps dans la création, et la gestion de ces formulaires.

créer formulaire python

CSRF, forloop, tout est prêt

C’est une obligation aujourd’hui, il faut gérer le CSRF sur les applications. Voici un formulaire de base Django, qu’on va créer en ajoutant un fichier details.html dans le dossier templates/ de l’app :


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


{% if error_message %}

<strong>{{ error_message }}</strong>

{% endif %}


<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>
{% endfor %}
<input type="submit" value="Vote" />
</form>

Donc le très classique token csrf à ajouter sous la déclaration du formulaire, mais ce qui me donne le sourire, c’est ce dictionnaire forloop. C’est un dictionnaire contenant les données suivantes :

{'revcounter0': 2, 'last': False, 'counter': 1, 'counter0': 0, 'first': True, 'parentloop': {}, 'revcounter': 3}

Je vous laisse deviner de quoi il s’agit, mais ça peut être bien utile pour savoir par exemple si on est sur la première/dernière itération.

Vous aurez noté la différence entre {% %} et {{ }} : D’un côté, on a les tags, qui servent à générer des fonctions pour étendre l’outil de templating. Vous pouvez les créer vous même pour les réutiliser plus tard. L’autre sert à afficher de la chaîne de caractère.

Maintenant qu’on a un formulaire de disponible, il va falloir créer la vue correspondantes (attention pour les dev php, les vues python sont des controllers php pour résumer), et mettre à jour d’anciennes vues.
Entre temps, je me suis aperçu que contrairement à ce que raconte le tuto, pour retourner un template (le fichier) depuis la vue, le paramètre du chemin vers du fichier est relatif.

il faut donc écrire :

return render(request, 'details.html', {'question': question})
#au lieu de 
return render(request, 'polls/details.html', {'question': question})

Alors c’est probablement suite à la déclaration app_name = ‘polls’ depuis le fichier urls.py de l’app.

Donc, on va mettre à jour la méthode index :

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .models import Question, Choice

def index(request):
    last_questions = Question.objects.order_by('-pub_date')[:5]
    context = {'last_questions': last_questions}
    return render(request, 'index.html', context)

On ajoute ensuite details et results, qui sont sensiblement identiques. Le but ici étant pour details, d’afficher le détail de la question, avec la possibilité de voter pour tel ou tel Choice (choix) :

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'details.html', {'question': question})


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'results.html', {'question': question})

Quand ces méthodes sont prêtes, on peut passer au POST, pour voter pour la question :

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'details.html', {
            'question' : question,
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes +=1
        selected_choice.save()

    return HttpResponseRedirect(reverse('polls:results', args=question_id))

Alors ce qui me perturbe un peu, c’est qu’à aucun moment on ne précise le verbe HTTP disponible pour la méthode (POST, GET, PATCH, PUT, DELETE).

Et n’oublions pas le template pour afficher le détail après le vote :


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



<ul>
{% for choice in question.choice.all %}

<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>

{% endfor %}
</ul>


<a href="{% url 'polls:detail' question.id %}">Re voter?</a>

Ce qu’on peut retenir :

D’abord, vous avez request.POST qui contient toutes les clés de votre requête HTTP. request.GET existe sous le même format.
On a aussi utilisé la gestion des exceptions python : Le programme va lever une erreur de type KeyError, si la clé choice ne se trouve pas dans le post. Ca permet de valider l’existence de la donnée dans le formulaire, et dans la base de donnée.
Il ya la méthode reverse(), qui si je comprends bien, sert à générer une url en fonction de son nom.

metrogeek

Comments 2

Laisser un commentaire