À propos de ce document
Ce document présente une introduction aux fonctionnalités de formulaires avec Django. Pour plus de détails sur des aspects spécifiques de l’API des formulaires, consultez The Forms API, Form fields et Form and field validation.
django.forms est la bibliothèque de gestion des formulaires de Django.
Même s’il est possible de traiter les envois de formulaires en utilisant simplement la classe HttpRequest de Django, l’utilisation de la bibliothèque de formulaires se charge d’un certain nombre de tâches liées aux formulaires. Avec cette bibliothèque, vous pouvez :
Afficher un formulaire HTML contenant des composants de formulaires générés automatiquement.
Vérifier les données envoyées par un ensemble de règles de validation.
Réafficher le formulaire en cas d’erreurs de validation.
Convertir les données de formulaires envoyées dans les types Python appropriés.
La bibliothèque se base sur ces concepts :
Une classe correspondant à un composant de formulaire HTML, par exemple <input type="text"> ou <textarea>. L’affichage du composant en HTML est aussi pris en charge.
Une classe responsable de la validation, par exemple un champ EmailField qui s’assure que ses données correspondent à une adresse électronique valable.
Un ensemble de champs qui savent comment valider leur contenu et s’afficher sous forme de code HTML.
Les ressources CSS et JavaScript requises pour afficher un formulaire.
La bibliothèque est découplée des autres composants de Django, tels que la couche de base de données, les vues et les gabarits. Elle ne dépend que des réglages de Django, de quelques fonctions utilitaires de django.utils ainsi que des fonctions de localisation de Django (mais rien ne vous oblige à utiliser les fonctions de localisation quand vous utilisez cette bibliothèque).
Un objet Form (formulaire) incorpore une série de champs de formulaires et un ensemble de règles de validation qui doivent être respectées pour que le formulaire soit accepté. Les classes de formulaires sont créées en héritant de django.forms.Form et font usage du style déclaratif qui devrait vous paraître familier si vous avez utilisé les modèles de base de données de Django.
Par exemple, considérons un formulaire servant à implémenter la fonctionnalité « Me contacter » sur un site Web personnel :
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
Un formulaire est composé d’objets Field (champs). Dans ce cas, notre formulaire possède quatre champs : subject, message, sender et cc_myself. CharField, EmailField et BooleanField ne sont que trois des types de champs disponibles ; une liste complète figure dans Form fields.
Si le formulaire sera utilisé pour directement ajouter ou modifier un modèle Django, vous pouvez utiliser un ModelForm pour éviter la duplication de la description de votre modèle.
La pratique standard du traitement d’un formulaire dans une vue ressemble à ceci :
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
Il existe trois chemins de code possibles ici :
Formulaire envoyé ? |
Données ? |
Ce qui se passe |
---|---|---|
Non envoyé |
Aucune |
Le gabarit reçoit une instance non renseignée de ContactForm. |
Envoyé |
Données non valides |
Le gabarit reçoit une instance renseignée de ContactForm. |
Envoyé |
Données valides |
Les données valides sont traitées. Redirection vers une page « Merci ». |
La distinction entre Bound and unbound forms est importante :
Un formulaire non renseigné n’a aucune donnée associée. Lorsqu’il est présenté à l’utilisateur, il sera vide ou ne contiendra que des valeurs par défaut.
Un formulaire renseigné contient des données envoyées et il est donc possible de lui demander si ces données sont valides. Si un formulaire renseigné non valide est affiché, il peut contenir des messages d’erreur intégrés indiquant à l’utilisateur quelles sont les données à corriger.
Pour savoir comment gérer les envois de fichiers avec votre formulaire, consultez Binding uploaded files to a form.
Quand is_valid() renvoie True, les données validées du formulaire se trouvent dans le dictionnaire form.cleaned_data. Ces données auront été gracieusement converties en types Python pour vous.
Note
À ce stade, vous pouvez toujours accéder directement aux données non validées dans request.POST, mais les données validées sont plus adéquates.
Dans l’exemple ci-dessus, cc_myself contient une valeur booléenne. De même, les champs tels que IntegerField et FloatField convertissent leurs valeurs en un type Python int et float, respectivement.
Les champs en lecture seule ne sont pas disponibles dans form.cleaned_data (et définir une valeur dans une méthode clean() personnalisée n’aura aucun effet). Ces champs sont affichés sous forme textuelle au lieu de zones de saisie, ce qui fait qu’ils ne sont pas renvoyés au serveur.
En poursuivant l’exemple précédent, voici comment les données de formulaires pourraient être traitées :
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
from django.core.mail import send_mail
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/') # Redirect after POST
Astuce
Pour en savoir plus sur l’envoi de courriels à partir de Django, consultez Envoi de messages électroniques.
Les formulaires sont conçus pour fonctionner avec le langage de gabarit de Django. Dans l’exemple ci-dessus, nous avons transmis l’instance de ContactForm au gabarit par l’intermédiaire de la variable de contexte form. Voici un exemple simple de gabarit :
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Le formulaire n’affiche que ses propres champs ; il vous revient d’écrire les balises englobantes <form> et le bouton d’envoi.
Si le formulaire permet d’envoyer des fichiers, prenez soin d’inclure enctype="multipart/form-data" dans la balise form. Si vous souhaitez écrire un gabarit générique fonctionnant avec ou sans envoi de fichier dans le formulaire, vous pouvez tester l’attribut is_multipart() du formulaire :
<form action="/contact/" method="post"
{% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
Formulaires et protection contre le « Cross site request forgery » (CSRF)
Django est livré avec une protection simple d’emploi contre les attaques Cross-Site Request Forgery. Lors de l’envoi d’un formulaire par la méthode POST avec la protection CSRF active, vous devez utiliser la balise de gabarit csrf_token comme dans l’exemple précédent. Cependant, comme la protection CSRF n’est pas directement liée aux formulaires dans les gabarits, cette balise est omise dans les exemples suivants de ce document.
form.as_p affiche le formulaire avec chacun de ses champs de formulaire et de ses étiquettes correspondantes englobé dans un paragraphe. Voici ce que ça donne pour notre gabarit d’exemple :
<form action="/contact/" method="post">
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
<input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
<input type="text" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<input type="submit" value="Submit" />
</form>
Notez que chaque champ de formulaire possède un attribut ID défini à id_<nom-du-champ> auquel fait référence la balise étiquette (<label>) accompagnant le champ. C’est important dans l’optique de rendre les formulaires accessibles par les aides techniques comme les logiciels de lecture d’écran. Vous pouvez aussi personnaliser la manière dont les étiquettes et les identifiants sont générés.
Vous pouvez également utiliser form.as_table pour afficher des lignes de tableau (vous devrez ajouter vous-même les balises <table>) et form.as_ul pour afficher des éléments de liste.
Si le code HTML généré par défaut ne vous convient pas, vous pouvez personnaliser complètement la manière dont le formulaire est affiché en utilisant le langage de gabarit de Django. En partant de l’exemple précédent :
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="id_message">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="id_sender">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="id_cc_myself">CC yourself?</label>
{{ form.cc_myself }}
</div>
<p><input type="submit" value="Send message" /></p>
</form>
Chaque champ de formulaire nommé peut être affiché dans le gabarit en utilisant {{ form.nom_du_champ }}, ce qui produira le code HTML requis pour afficher le composant de formulaire. La syntaxe {{ form.nom_du_champ.errors }} affiche une liste des erreurs du formulaire, sous forme de liste non ordonnée. Cela pourrait ressembler à ceci :
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
La liste possède une classe CSS errorlist pour vous permettre de mettre en forme son apparence. Si vous souhaitez personnaliser davantage l’affichage des erreurs, vous pouvez le faire par une boucle :
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
Si vous utilisez le même code HTML pour tous vos champs de formulaire, vous pouvez réduire la duplication de code en effectuant une boucle sur chaque champ en utilisant l’opérateur {% for %}:
<form action="/contact/" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
</form>
Dans cette boucle, {{ field }} est une instance de BoundField. BoundField possède également les attributs suivants qui peuvent être utiles dans vos gabarits :
L’étiquette du champ, par exemple Adresse de courriel.
L’étiquette du champ placée dans la balise HTML <label>, par exemple <label for="id_email">Adresse de courriel</label>
La valeur du champ, par exemple quelqu-un@example.com
Le nom du champ tel qu’il sera utilisé dans le nom de champ de la balise input. Il prend en compte le préfixe de formulaire, si celui-ci est défini.
Tout texte d’aide associé au champ.
Affiche une liste <ul class="errorlist"> contenant toute erreur de validation correspondant à ce champ. Vous pouvez personnaliser la présentation des erreurs avec une boucle {% for error in field.errors %}. Dans ce cas, chaque objet de la boucle est une simple chaîne de caractères contenant le message d’erreur.
Cet attribut vaut True si le champ de formulaire est un champ masqué, sinon il vaut False. Ce n’est pas particulièrement utile comme variable de gabarit, mais pourrait être utile dans des tests conditionnels tels que :
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
L’instance Field de la classe de formulaire que cet objet BoundField adapte. Vous pouvez l’utiliser pour accéder aux attributs de Field, par exemple {{ char_field.field.max_length }}.
Si votre site utilise la même logique d’affichage des formulaires à plusieurs endroits, vous pouvez réduire la duplication en enregistrant la boucle de formulaire dans un gabarit autonome et en employant la balise include afin de réutiliser ce contenu dans d’autres gabarits :
<form action="/contact/" method="post">
{% include "form_snippet.html" %}
<p><input type="submit" value="Send message" /></p>
</form>
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
Si l’objet formulaire transmis au gabarit possède un nom différent dans le contexte, vous pouvez lui donner un alias en utilisant le paramètre with de la balise include:
<form action="/comments/add/" method="post">
{% include "form_snippet.html" with form=comment_form %}
<p><input type="submit" value="Submit comment" /></p>
</form>
Si vous constatez que vous reproduisez souvent ce même code, il vous faut peut-être envisager la création d’une balise d’inclusion personnalisée.
Cette page aborde les généralités, mais les formulaires peuvent faire bien d’autres choses encore :
Voir aussi
Contient la référence d’API complète, y compris les champs de formulaire, les composants de formulaire et la validation des champs et des formulaires.
Jan 13, 2016