Utilisation des formulaires

À propos de ce document

Ce document présente une introduction aux bases des formulaires web et à la manière dont ils sont traités par Django. Pour plus de détails sur des aspects spécifiques de l’API des formulaires, consultez L’API des formulaires, Champs de formulaires, et La validation de formulaires et de champs.

À moins que vous n’ayez l’intention de construire des sites Web et des applications qui ne font rien d’autre que de publier du contenu, et n’acceptant aucune saisie de la part de ses visiteurs, vous allez avoir besoin de comprendre et d’utiliser des formulaires.

Django fournit un certain nombre d’outils et de bibliothèques pour vous aider à créer des formulaires de saisie pour les visiteurs du site, puis pour aider à traiter et à répondre à ces saisies.

Formulaires HTML

En HTML, un formulaire est un ensemble d’éléments à l’intérieur des balises <form>...</form> qui permettent à un visiteur d’effectuer des actions comme saisir du texte, sélectionner des options, manipuler des objets ou des contrôles, et ainsi de suite, puis d’envoyer ces informations au serveur.

Certains de ces éléments d’interface de formulaires - boîtes de saisie de texte ou cases à cocher - sont intégrés à HTML. D’autres éléments sont beaucoup plus complexes ; une interface qui affiche un sélecteur de date ou qui permet de déplacer un curseur ou de contrôler un autre élément graphique utilise généralement du code JavaScript et CSS, ainsi que des éléments <input> de formulaires HTML pour produire ce genre d’effets.

En plus de ses éléments <input>, un formulaire doit préciser deux choses :

  •  : l’URL vers laquelle les données correspondant à la saisie de l’utilisateur doivent être renvoyées
  • comment : la méthode HTTP utilisée pour renvoyer les données

Par exemple, le formulaire de connexion pour l’administration de Django contient plusieurs éléments <input>: un de type="text" pour le nom d’utilisateur, un de type="password" pour le mot de passe, et un de type="submit" pour le bouton « Connexion ». Il contient également des champs de texte cachés que l’utilisateur ne voit pas, mais que Django utilise pour déterminer ce qu’il faut faire après la connexion.

Il indique également au navigateur que les données du formulaire doivent être envoyées à l’URL spécifiée dans l’attribut action de la balise <form> (/admin/) et qu’elles doivent être envoyées en utilisant le mécanisme HTTP spécifié par l’attribut method (post).

Lorsque le bouton <input type="submit" value="Connexion"> est déclenché, les données sont renvoyées à /admin/.

GET et POST

GET et POST sont les seules méthodes HTTP à utiliser dans les formulaires.

Le formulaire de connexion de Django est renvoyé en utilisant la méthode POST, par laquelle le navigateur regroupe les données du formulaire, les encode pour la transmission, les envoie au serveur, puis reçoit la réponse en retour.

GET, en revanche, regroupe les données fournies dans une chaîne et l’utilise pour composer une URL. L’URL contient l’adresse à laquelle les données doivent être envoyées, ainsi que les clés et les valeurs fournies. Vous pouvez en voir un exemple si vous effectuez une recherche dans la documentation de Django, car cela va produire une URL de la forme https://docs.djangoproject.com/search/?q=forms&release=1.

GET et POST sont généralement utilisées à des fins différentes.

Toute requête pouvant être utilisée pour modifier l’état du système, par exemple une requête qui applique des changements en base de données, devrait utiliser POST. GET ne devrait être employée que pour des requêtes qui n’affectent pas l’état du système.

GET ne conviendrait pas non plus pour un formulaire de changement de mot de passe, car le mot de passe apparaîtrait en clair dans l’URL ainsi que dans l’historique du navigateur et les journaux du serveur. Elle ne conviendrait pas non plus pour des données volumineuses ou pour des données binaires telles que pour une image. Une application Web utilisant des requêtes GET pour des formulaires administratifs ne serait pas sécurisée : il est facile pour un attaquant de simuler une requête de formulaire pour obtenir l’accès à des parties sensibles du système. Les requêtes POST accompagnées par d’autres protections comme la protection CSRF de Django offrent un bien meilleur contrôle sur les accès.

D’autre part, GET convient pour des interfaces comme un formulaire de recherche Web, car les URL qui représentent une requête GET peuvent être facilement conservées dans un signet, partagées ou ré-envoyées.

Le rôle de Django dans les formulaires

La gestion des formulaires est une affaire complexe. Considérez l’application d’administration de Django où de nombreuses données de différents types doivent être préparées pour être affichées dans un formulaire, produites en HTML, éditées par une interface conviviale, renvoyées vers le serveur, validées et nettoyées, et finalement enregistrées ou transmises pour traitement ultérieur.

La fonctionnalité des formulaires de Django peut simplifier et automatiser de larges portions de ce travail et peut aussi le faire de manière plus sécurisée que la plupart des programmeurs ne pourraient le faire en écrivant leur propre code.

Django gère trois parties distinctes du travail induit par les formulaires :

  • préparation et restructuration des données en vue de leur présentation
  • création des formulaires HTML pour les données
  • réception et traitement des formulaires et des données envoyés par le client

Il est possible d’écrire du code qui fait tout cela manuellement, mais Django peut s’en charger à votre place.

Les formulaires dans Django

Nous avons brièvement décrit les formulaires HTML, mais un objet HTML <form> n’est qu’un élément de la machinerie nécessaire.

Dans le contexte d’une application Web, « formulaire » peut se référer à cette balise HTML <form>, à la classe Form de Django qui la produit, aux données structurées renvoyées lorsque le formulaire est soumis, ou encore au fonctionnement de bout en bout de ces différentes parties.

La classe Form de Django

La classe Form de Django se situe au cœur de ce système de composants. De la même façon qu’un modèle Django décrit la structure logique d’un objet, son comportement et la manière dont ses parties nous sont présentées, une classe Form décrit un formulaire et détermine son fonctionnement et son apparence.

De la même façon que les champs d’une classe de modèle correspondent à des champs de base de données, les champs d’une classe de formulaire correspondent aux éléments <input> d’un formulaire HTML (un ModelForm fait correspondre les champs d’une classe de modèle à des éléments <input> d’un formulaire HTML via un formulaire Form; cela constitue la base de l’interface d’administration de Django).

Les champs d’un formulaire sont eux-mêmes des classes ; elles gèrent les données de formulaire et s’occupent de la validation lorsque des données de formulaires sont reçues. Un champ DateField et un champ FileField gèrent des types de données très différents et doivent procéder à des actions différentes.

Un champ de formulaire est présenté dans une interface de navigateur sous forme de « composant » HTML, un élément d’interface utilisateur. Chaque type de champ contient une classe Widget appropriée par défaut, mais celles-ci peuvent être remplacées au besoin.

Instanciation, traitement et rendu des formulaires

Lors du rendu d’un objet Django pour son affichage, il s’agit généralement de :

  1. obtenir l’élément dans la vue (le récupérer à partir de la base de données, par exemple)
  2. le transmettre au contexte de gabarit
  3. le transformer en balisage HTML en utilisant des variables de gabarit

L’affichage d’un formulaire dans un gabarit suit à peu près le même processus que pour tout autre type d’objet, mais il y a tout de même certaines différences notables.

Dans le cas d’une instance de modèle ne contenant aucune donnée, il n’y aura pas beaucoup de sens d’en faire quoi que ce soit dans un gabarit. En revanche, il est totalement raisonnable de vouloir afficher un formulaire vierge, c’est ce qu’il faut faire lorsqu’on veut que quelqu’un le remplisse.

Ainsi, lorsque nous manipulons une instance de modèle dans une vue, nous la récupérons typiquement à partir de la base de données. Lorsque nous manipulons un formulaire, nous en créons typiquement une instance dans la vue.

When we instantiate a form, we can opt to leave it empty or prepopulate it, for example with:

  • des données provenant d’une instance de modèle enregistrée (comme dans le cas des formulaires d’administration pour l’édition)
  • des données que nous avons obtenues à partir d’autres sources
  • des données reçues d’un envoi de formulaire HTML

Le dernier de ces cas est le plus intéressant, car c’est ce qui permet aux utilisateurs de ne pas seulement lire un site Web, mais aussi de renvoyer des informations aux sites Web.

Construction d’un formulaire

Le travail à effectuer

Supposons que vous vouliez créer un formulaire simple sur votre site dans le but d’obtenir le nom de l’utilisateur. Voici ce qu’il faudrait obtenir dans le navigateur :

<form action="/your-name/" method="post">
    <label for="your_name">Your name: </label>
    <input id="your_name" type="text" name="your_name" value="{{ current_name }}">
    <input type="submit" value="OK">
</form>

Le navigateur saura alors qu’il doit renvoyer les données du formulaire vers l’URL /your-name/, en utilisant la méthode POST. Il affichera un champ de texte libellé « Your name: » et un bouton intitulé « OK ». Si le contexte de gabarit contient une variable current_name, celle-ci sera utilisée pour pré-remplir le champ your_name.

Il faudra une vue qui produit le gabarit contenant le formulaire HTML et qui puisse fournir le champ current_name si nécessaire.

Lorsque le formulaire aura été envoyé, la requête POST envoyée au serveur contiendra les données du formulaire.

Mais il sera également nécessaire d’avoir une vue répondant à l’URL /your-name/ qui se chargera de trouver les paires clé-valeur dans la requête, puis de les traiter.

This is a very simple form. In practice, a form might contain dozens or hundreds of fields, many of which might need to be prepopulated, and we might expect the user to work through the edit-submit cycle several times before concluding the operation.

On peut attendre du navigateur qu’il s’occupe d’une partie de la validation, même avant que le formulaire ne soit envoyé. Peut-être que certains champs seront bien plus complexes, permettant par exemple de choisir des dates dans un calendrier.

Compte tenu de tout ceci, il est bien plus avantageux que Django se charge lui-même de la plupart du travail.

Construction d’un formulaire dans Django

La classe Form

Nous savons déjà à quoi notre formulaire HTML doit ressembler. Notre point de départ dans Django est le suivant :

forms.py
from django import forms

class NameForm(forms.Form):
    your_name = forms.CharField(label='Your name', max_length=100)

Cela définit une classe Form comportant un seul champ (your_name). Nous avons attribué une étiquette conviviale à ce champ ; celle-ci apparaîtra dans la balise <label> au moment de l’affichage (bien que dans ce cas, le contenu indiqué dans label est en réalité identique à celui qui aurait été généré automatiquement si nous n’avions rien fait).

La longueur maximale du champ est définie par max_length. Cela fait deux choses : la balise HTML <input> reçoit l’attribut maxlength="100" (afin que le navigateur empêche lui-même la saisie d’un plus grand nombre de caractères), et ultérieurement lorsque Django reçoit en retour les données de formulaire, il valide que les données respectent cette longueur.

Une instance de Form possède une méthode is_valid() qui procède aux routines de validation pour tous ses champs. Lorsque la méthode est appelée et que tous les champs contiennent des données valables, celle-ci :

  • renvoie True;
  • insère les données du formulaire dans l’attribut cleaned_data.

Le formulaire complet, lorsqu’il est affiché pour la première fois, ressemble à ceci :

<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100" required>

Notez qu’il n’inclut pas les balises <form> ni de bouton d’envoi. Ces éléments doivent être ajoutés par celui qui rédige le gabarit.

La vue

Les données de formulaire renvoyés à un site Web Django sont traitées par une vue, en principe la même qui a servi à produire le formulaire. Cela permet de réutiliser une partie de la même logique.

Pour traiter le formulaire, nous devons en créer une instance dans la vue à destination de l’URL à laquelle il doit apparaître :

views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import NameForm

def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect('/thanks/')

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, 'name.html', {'form': form})

Si nous arrivons dans cette vue avec une requête GET, la vue crée une instance de formulaire vierge et la place dans le contexte de gabarit en vue de son affichage. C’est à quoi l’on peut s’attendre lors du premier accès à l’URL en question.

Si le formulaire est envoyé par une requête POST, la vue crée également une instance de formulaire et la complète avec les données reçues à partir de la requête : form = NameForm(request.POST). C’est ce qu’on appelle « lier les données au formulaire » (il s’agit maintenant d’un formulaire lié, « bound » en anglais).

La méthode is_valid() est appelée ; si elle ne renvoie pas True, on se retrouve au stade du gabarit contenant le formulaire. Mais cette fois, le formulaire n’est plus vierge (non lié ou unbound) ce qui fait que le formulaire HTML sera rempli avec les données saisies précédemment, données qui peuvent être modifiées et corrigées selon les besoins.

Si is_valid() renvoie True, toutes les données validées du formulaire sont alors accessibles dans l’attribut cleaned_data. Ces données peuvent être utilisées pour mettre à jour la base de données ou effectuer d’autres opérations avant de renvoyer au navigateur une redirection HTTP lui indiquant l’URL à recharger.

Le gabarit

Il n’y a pas grand chose à faire dans le gabarit name.html:

<form action="/your-name/" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit">
</form>

Tous les champs de formulaire et leurs attributs seront convertis en balises HTML à partir de {{ form }} par le langage de gabarit de Django.

Formulaires et protection contre le « Cross site request forgery » (CSRF)

Django est livré avec une protection simple d’emploi contre les attaques de type Cross Site Request Forgeries. Lors de l’envoi d’un formulaire par la méthode POST et 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.

Types de composants HTML5 et validation par le navigateur

Si un formulaire contient un champ de type URLField, EmailField ou tout type de champ nombre entier, Django fait appel aux composants HTML5 (input) de type url, email et number. Par défaut, les navigateurs appliquent souvent leur propre validation de ces champs, qui peut être plus stricte que celle de Django. Si vous voulez échapper à cette validation, ajoutez l’attribut novalidate sur la balise form ou définissez un autre composant de formulaire pour le champ, comme par exemple TextInput.

Nous possédons maintenant un formulaire Web fonctionnel, défini par une instance Form de Django, traité par une vue et affiché sous forme de balise HTML <form>.

C’est tout ce dont vous avez besoin pour commencer, mais l’infrastructure des formulaires a beaucoup plus à vous offrir. À partir du moment où vous comprenez les bases du processus décrit ci-dessus, il est bon de connaître les autres fonctionnalités mises à disposition par le système des formulaires et d’en savoir un peu plus au sujet de la machinerie sous-jacente.

Plus de détails sur les classes Form de Django

Toutes les classes de formulaires sont créées comme sous-classes de django.forms.Form ou de django.forms.ModelForm. ModelForm peut être considéré comme une sous-classe de Form. Form et ModelForm héritent effectivement de comportements communs provenant de la classe (privée) BaseForm, mais ce détail d’implémentation est rarement significatif.

Modèles et formulaires

En fait, si un formulaire est destiné à ajouter ou modifier directement un modèle Django, un formulaire ModelForm peut vous économiser beaucoup de temps, d’effort et de code, car il s’occupe de construire un formulaire avec tous les champs et attributs appropriés à partir d’une classe Model.

Instances de formulaires liées et non liées

La distinction entre Formulaires liés et non liés 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.

L’attribut is_bound d’un formulaire indique si des données ont été liées au formulaire ou pas.

Plus de détails sur les champs

Voici un formulaire un peu plus utile que notre exemple minimal ci-dessus, que nous pourrions utiliser pour implémenter une fonctionnalité « Contactez-moi » sur un site Web personnel :

forms.py
from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

Le formulaire précédent comportait un seul champ, your_name, de type CharField. Dans ce cas, le 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 se trouve dans Champs de formulaires.

Composants de formulaires (« widgets »)

À chaque champ de formulaire correspond une classe Widget, qui elle-même se réfère à un composant de formulaire HTML comme par exemple <input type="text">.

Dans la plupart des cas, le composant par défaut du champ convient bien. Par exemple, le composant par défaut du champ CharField est TextInput, qui produit une balise <input type="text"> en HTML. Si au contraire vous aviez souhaité une balise <textarea>, il aurait fallu définir le composant approprié lors de la définition du champ de formulaire, comme nous l’avons fait pour le champ message.

Données de champ

Quelles que soient les données envoyées avec un formulaire, au moment où elles ont été validées avec succès suite à l’appel de is_valid() (et que is_valid() a renvoyé True), les données de formulaire validées 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 du formulaire de contact, cc_myself sera une valeur booléenne. De la même manière, des champs de type IntegerField et FloatField convertissent les valeurs en types Python int et float, respectivement.

Voici comment les données de formulaire pourraient être traitées dans la vue qui gère ce formulaire :

views.py
from django.core.mail import send_mail

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)

    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/')

Astuce

Pour en savoir plus sur l’envoi de courriels à partir de Django, consultez Envoi de messages électroniques.

Certains types de champ ont besoin de traitement supplémentaire. Par exemple, les fichiers téléversés via un formulaire doivent être traités différemment (ils sont accessibles par request.FILES, et non pas par request.POST). Pour plus de détails sur la façon de gérer des téléversements de fichiers avec un formulaire, consultez Liaison de fichiers téléversés avec un formulaire.

Formulaires et gabarits

Tout ce qui est nécessaire pour qu’un formulaire soit inclus dans un gabarit est de placer l’instance de formulaire dans le contexte du gabarit. Ainsi, si le formulaire est appelé form dans le contexte, {{ form }} suffira à afficher ses éléments <label> et <input> de manière appropriée.

Compléments HTML pour les formulaires dans les gabarits

N’oubliez pas que le rendu HTML d’un formulaire n’inclut pas la balise <form> englobante, ni le composant submit pour l’envoi du formulaire. C’est à vous d’ajouter ces éléments.

Gabarits de formulaire réutilisables

The HTML output when rendering a form is itself generated via a template. You can control this by creating an appropriate template file and setting a custom FORM_RENDERER to use that form_template_name site-wide. You can also customize per-form by overriding the form’s template_name attribute to render the form using the custom template, or by passing the template name directly to Form.render().

The example below will result in {{ form }} being rendered as the output of the form_snippet.html template.

Dans vos gabarits :

# In your template:
{{ form }}

# In form_snippet.html:
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

Then you can configure the FORM_RENDERER setting:

settings.py
from django.forms.renderers import TemplatesSetting

class CustomFormRenderer(TemplatesSetting):
    form_template_name = "form_snippet.html"

FORM_RENDERER = "project.settings.CustomFormRenderer"

… or for a single form:

class MyForm(forms.Form):
    template_name = "form_snippet.html"
    ...

… or for a single render of a form instance, passing in the template name to the Form.render(). Here’s an example of this being used in a view:

def index(request):
    form = MyForm()
    rendered_form = form.render("form_snippet.html")
    context = {'form': rendered_form}
    return render(request, 'index.html', context)

See Affichage des formulaires en HTML for more details.

Changed in Django 4.0:

La production des formulaires sur la base des gabarits a été ajoutée.

Changed in Django 4.1:

The ability to set the default form_template_name on the form renderer was added.

Options d’affichage des formulaires

Il existe toutefois d’autres options pour les paires <label>/<input>:

  • {{ form.as_div }} will render them wrapped in <div> tags.
  • {{ form.as_table }} will render them as table cells wrapped in <tr> tags.
  • {{ form.as_p }} will render them wrapped in <p> tags.
  • {{ form.as_ul }} will render them wrapped in <li> tags.

Notez que vous devrez ajouter vous-même les éléments <table> ou <ul> autour du contenu produit.

Voici ce qu’affiche {{ form.as_p }} pour notre instance de ContactForm:

<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
    <textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
    <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

Notez que chaque champ de formulaire reçoit un attribut ID défini à id_<nom-de-champ> qui est référencé par la balise label correspondante. C’est important pour garantir que les formulaires sont accessibles aux aides techniques du genre logiciel de lecture d’écran. Vous pouvez aussi personnaliser la façon dont les éléments label et id sont générés.

Voir Affichage des formulaires en HTML pour plus d’informations à ce sujet.

Affichage manuel des champs

Laisser Django afficher un à un les champs du formulaire n’est pas la seule possibilité ; on peut tout à fait afficher soi-même les champs (par exemple pour changer leur ordre d’apparition). Chaque champ est accessible en tant qu’attribut du formulaire avec la syntaxe {{ form.nom_du_champ }}, ce qui, dans un gabarit Django, produira son affichage de manière appropriée. Par exemple :

{{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Email subject:</label>
    {{ form.subject }}
</div>
<div class="fieldWrapper">
    {{ form.message.errors }}
    <label for="{{ form.message.id_for_label }}">Your message:</label>
    {{ form.message }}
</div>
<div class="fieldWrapper">
    {{ form.sender.errors }}
    <label for="{{ form.sender.id_for_label }}">Your email address:</label>
    {{ form.sender }}
</div>
<div class="fieldWrapper">
    {{ form.cc_myself.errors }}
    <label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
    {{ form.cc_myself }}
</div>

Une balise <label> complète peut aussi être générée au moyen de label_tag(). Par exemple :

<div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
</div>

Affichage des messages d’erreur de formulaires

Le prix de cette flexibilité est un effort un peu plus grand. Jusqu’à ce stade, nous n’avions pas à nous préoccuper de l’affichage des erreurs du formulaire, car cela se faisait automatiquement. Dans cet exemple, il a fallu s’assurer que les erreurs de chaque champ et les erreurs globales du formulaire soient effectivement affichées. Remarquez {{ form.non_field_errors }} au sommet du formulaire ainsi que l’expression de gabarit concernant les erreurs de chaque champ.

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 %}

Les erreurs non liées à un champ (ou les erreurs de champs cachés qui sont affichées au sommet du formulaire lorsqu’on utilise des utilitaires comme form.as_p()) seront dotées d’une classe supplémentaire nonfield pour aider à faire la distinction avec les erreurs spécifiques à un champ. Par exemple, {{ form.non_field_errors }} ressemblerait à :

<ul class="errorlist nonfield">
    <li>Generic validation error</li>
</ul>

Voir L’API des formulaires pour plus de détails sur les erreurs, la mise en forme et la manipulation des attributs de formulaire dans les gabarits.

Boucles sur champs de formulaires

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 %}:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
        <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
    </div>
{% endfor %}

Voici quelques attributs de champ utiles :

{{ field.errors }}
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 chaîne de caractères contenant le message d’erreur.
{{ field.field }}
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 }}.
{{ field.help_text }}
Tout texte d’aide associé au champ.
{{ field.html_name }}
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.
{{ field.id_for_label }}
L’attribut id utilisé pour ce champ (id_email dans l’exemple ci-dessus). Si vous construisez vous-même l’étiquette du champ, il peut être avantageux d’utiliser ceci à la place de label_tag. C’est aussi utile par exemple si vous avez du code JavaScript en ligne et que vous vouliez éviter de figer l’identifiant du champ.
{{ field.is_hidden }}
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 %}
{{ field.label }}
L’étiquette du champ, par exemple Adresse de courriel.
{{ field.label_tag }}

L’intitulé du champ placé dans la balise HTML <label> appropriée. Cela comprend le paramètre label_suffix du formulaire. Par exemple, la valeur label_suffix par défaut est un caractère deux-points :

<label for="id_email">Email address:</label>

{{ field.legend_tag }}

New in Django 4.1.

Similar to field.label_tag but uses a <legend> tag in place of <label>, for widgets with multiple inputs wrapped in a <fieldset>.

{{ field.use_fieldset }}

New in Django 4.1.

This attribute is True if the form field’s widget contains multiple inputs that should be semantically grouped in a <fieldset> with a <legend> to improve accessibility. An example use in a template:

{% if field.use_fieldset %}
  <fieldset>
  {% if field.label %}{{ field.legend_tag }}{% endif %}
{% else %}
  {% if field.label %}{{ field.label_tag }}{% endif %}
{% endif %}
{{ field }}
{% if field.use_fieldset %}</fieldset>{% endif %}
{{ field.value }}
La valeur du champ, par exemple quelqu-un@example.com.

Voir aussi

Pour une liste complète des attributs et méthodes, voir BoundField.

Boucles sur les champs masqués et visibles

Si vous affichez manuellement un formulaire dans un gabarit, sans faire appel à l’affichage par défaut des formulaires de Django, il peut être nécessaire de traiter différemment les champs <input type="hidden"> des autres champs non masqués. Par exemple, comme les champs masqués ne produisent pas de contenu visible, l’affichage de messages d’erreur « à côté » du champ pourrait générer de la confusion pour les utilisateurs ; il faut donc gérer différemment les erreurs de ce type de champ.

Django fournit deux méthodes qui permettent de tourner en boucle indépendamment sur les champs visibles et masqués : hidden_fields() et visible_fields(). Voici une modification d’un exemple précédent en utilisant ces deux méthodes :

{# Include the hidden fields #}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{# Include the visible fields #}
{% for field in form.visible_fields %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

Cet exemple ne gère pas du tout les erreurs des champs masqués. En principe, une erreur dans un champ masqué est un signe de manipulation abusive d’un formulaire, puisque l’interaction normale avec un formulaire ne les modifie pas. Cependant, vous pourriez facilement ajouter aussi une forme d’affichage pour ces erreurs de formulaire.

Back to Top