# Documentation Django 6.0.7

# L’API des formulaires

À propos de ce document

Ce document aborde en détails l’API des formulaires de Django. Il est recommandé de lire d’abord l’introduction à l’utilisation des formulaires.

## Formulaires liés et non liés

Une instance `Form` est soit liée (bound) à un jeu de données, soit non liée (unbound).

- Si elle est liée à un jeu de données, elle est capable de valider ces données et d’afficher un formulaire en HTML en y incluant les données.

- Si elle est non liée, elle ne peut pas procéder à la validation (car il n’y a aucune donnée à valider !), mais elle peut tout de même afficher un formulaire HTML vierge.

class Form

Pour créer une instance `Form` non liée, instanciez la classe :

    >>> f = ContactForm()

Pour lier des données au formulaire, transmettez ces données sous forme de dictionnaire comme premier paramètre au constructeur de la classe `Form`:

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)

Dans ce dictionnaire, les clés sont les noms de champs qui correspondent aux attributs de la classe `Form`. Les valeurs sont les données que vous souhaitez valider. Il s’agit en principe de chaînes de caractères, mais ce n’est pas une obligation. Le type des données transmises dépend du champ `Field`, comme nous allons le voir dans un moment.

Form.is_bound

Si vous avez besoin de faire la différence entre des instances de formulaires liés et non liés au moment de l’exécution, vous pouvez vous baser sur l’attribut `is_bound` du formulaire :

    >>> f = ContactForm()
    >>> f.is_bound
    False
    >>> f = ContactForm({"subject": "hello"})
    >>> f.is_bound
    True

Notez que le fait de transmettre un dictionnaire vide crée un formulaire lié avec des données vides :

    >>> f = ContactForm({})
    >>> f.is_bound
    True

Si vous souhaitez modifier d’une quelconque manière les données d’une instance `Form` liée ou si vous aimeriez lier une instance `Form` non liée à certaines données, créez une nouvelle instance de `Form`. Il n’est pas possible de modifier les données dans une instance `Form`. Dès qu’une instance `Form` a été créée, ses données doivent être considérées comme immuables, que les données existent ou non.

## Utilisation de formulaires pour valider des données

Form.clean()

L’implémentation d’une méthode `clean()` pour un formulaire se justifie lorsque de la validation personnalisée est nécessaire pour des champs interdépendants. Voir Nettoyage et validation de champs qui dépendent l’un de l’autre pour des exemples d’utilisation.

Form.is_valid()

La tâche principale d’un objet `Form` est de valider des données. Disposant d’une instance `Form` liée, appelez la méthode `is_valid()` pour procéder à la validation et renvoyer une valeur booléenne indiquant si les données sont valides :

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True

Let’s try with some invalid data. In this case, `subject` is blank (an error, because all fields are required by default) and `contact_email` is not a valid email address:

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "contact_email": "invalid email address",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    False

Form.errors

Accédez à l’attribut `errors` pour obtenir un dictionnaire des messages d’erreur :

    >>> f.errors
    {'subject': ['This field is required.'],
     'contact_email': ['Enter a valid email address.']}

Dans ce dictionnaire, les clés correspondent aux noms de champs et les valeurs à des listes de chaînes représentant les messages d’erreur. Ceux-ci sont stockés dans des listes car un champ peut générer plusieurs messages d’erreur.

Vous pouvez accéder à `errors` sans devoir appeler d’abord `is_valid()`. Les données du formulaire seront validées lors du premier appel à `is_valid()` ou du premier accès à `errors`.

Les routines de validation ne sont appelées qu’une seule fois, même si vous appelez plusieurs fois `is_valid()` ou que vous accédez plusieurs fois à `errors`. Cela signifie que si la validation provoque des effets de bord, ceux-ci ne sont produits qu’une seule fois.

Form.errors.as_data()

Renvoie un dictionnaire faisant correspondre les champs à leur instance `ValidationError` originale.

    >>> f.errors.as_data()
    {'subject': [ValidationError(['This field is required.'])],
     'contact_email': [ValidationError(['Enter a valid email address.'])]}

Utilisez cette méthode chaque fois qu’il y a besoin d’identifier une erreur par son `code`. Cela permet des choses telles que la réécriture du message d’erreur ou l’écriture d’une logique personnalisée dans une vue lorsqu’une erreur donnée est présente. Elle peut également être utilisée pour sérialiser les erreurs dans un format personnalisé (par ex. XML) ; par exemple, `as_json()` se base sur `as_data()`.

La nécessité de la méthode `as_data()` s’explique par la rétrocompatibilité. Précédemment, les instances `ValidationError` étaient perdues dès le moment où leurs messages d’erreur étaient ajoutés dans leur état rendu au dictionnaire `Form.errors`. Idéalement, `Form.errors` aurait dû stocker les instances `ValidationError` et des méthodes préfixées par `as_` auraient pu produire leur rendu final, mais il a fallu procéder d’une manière inverse afin de ne pas casser du code qui s’attendait à trouver des messages d’erreur « finaux » dans `Form.errors`.

Form.errors.as_json(escape_html=False)

Returns a string with the errors serialized as JSON.

    >>> f.errors.as_json()
    '{"subject": [{"message": "This field is required.", "code": "required"}],
     "contact_email": [{"message": "Enter a valid email address.", "code": "invalid"}]}'

Par défaut, `as_json()` n’échappe pas son contenu. Si vous l’utilisez dans un contexte comme des requêtes AJAX vers une vue de formulaire où le client interprète la réponse et insère les erreurs dans la page, il faut vous assurer de bien échapper le contenu du côté client pour éviter l’éventualité d’une attaque de script intersite. Vous pouvez le faire en JavaScript avec `element.textContent = errorText` ou en jQuery avec `$(el).text(errorText)` (plutôt que sa fonction `.html()`).

Si pour une raison précise vous ne souhaitez pas utiliser l’échappement du côté client, vous pouvez aussi définir `escape_html=True` et les messages d’erreur seront échappés afin de pouvoir les utiliser directement en HTML.

Form.errors.get_json_data(escape_html=False)

Renvoie les erreurs sous forme de dictionnaire prêt à être sérialisé en JSON. `Form.errors.as_json()` renvoie du JSON sérialisé, alors que cette methode renvoie les données d’erreur avant leur sérialisation.

Le paramètre `escape_html` possède le même comportement que pour `Form.errors.as_json()`.

Form.add_error(field, error)

Cette méthode permet d’ajouter des erreurs à des champs spécifiques depuis la méthode `Form.clean()` elle-même ou carrément depuis l’extérieur du formulaire, par exemple depuis une vue.

Le paramètre `field` est le nom du champ auquel les erreurs seront attribuées. Si sa valeur est `None`, l’erreur est traitée comme une erreur non liée à un champ, et fera partie des erreurs renvoyées par `Form.non_field_errors()`.

Le paramètre `error` peut être une chaîne ou de préférence une instance de `ValidationError`. Consultez Génération de ValidationError pour des conseils de bonnes pratiques lors de la définition d’erreurs de formulaire.

Notez que `Form.add_error()` enlève automatiquement les champs correspondants du dictionnaire `cleaned_data`.

Form.has_error(field, code=None)

Cette méthode renvoie une valeur booléenne indiquant si un champ contient une erreur avec un `code` d’erreur spécifique. Si `code` vaut `None`, la méthode renvoie `True` si le champ contient n’importe quelle erreur.

Pour vérifier la présence d’erreurs non liées aux champs, indiquez `NON_FIELD_ERRORS` dans le paramètre `field`.

Form.non_field_errors()

Cette méthode renvoie la liste des erreurs dans `Form.errors` qui ne sont pas associées à un champ particulier. Cela comprend les erreurs `ValidationError` qui sont générées dans `Form.clean()` et les erreurs ajoutées par `Form.add_error(None, "...")`.

### Comportement des formulaires non liés

Il n’y a pas de raison de vouloir valider un formulaire sans données, mais pour que cela soit dit, voici ce qui se passe avec des formulaires non liés :

    >>> f = ContactForm()
    >>> f.is_valid()
    False
    >>> f.errors
    {}

## Valeurs initiales de formulaires

Form.initial

Le paramètre `initial` permet de déclarer des valeurs initiales des champs de formulaire au moment de l’exécution. Par exemple, il peut être intéressant de pré-remplir un champ `username` avec le nom d’utilisateur de la session en cours.

Pour faire cela, utilisez le paramètre `initial` d’une instance `Form`. Quand il est présent, ce paramètre doit être un dictionnaire faisant correspondre des noms de champs à des valeurs initiales. N’incluez que les champs pour lesquels une valeur initiale existe ; il n’est pas nécessaire d’inclure tous les champs du formulaire. Par exemple :

    >>> f = ContactForm(initial={"subject": "Hi there!"})

Ces valeurs ne sont affichées que pour les formulaires non liés et elles ne servent pas à fournir des valeurs par défaut si un champ particulier n’est pas renseigné.

Si un champ `Field` définit `initial` et que vous incluez `initial` lors de la création du formulaire, c’est ce dernier qui prend le dessus. Dans cet exemple, `initial` est renseigné à la fois au niveau du champ et au niveau de l’instance de formulaire, et c’est ce dernier qui a la priorité :

    >>> from django import forms
    >>> class CommentForm(forms.Form):
    ...     name = forms.CharField(initial="class")
    ...     url = forms.URLField()
    ...     comment = forms.CharField()
    ...
    >>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
    >>> print(f)
    <div>Name:<input type="text" name="name" value="instance" required></div>
    <div>Url:<input type="url" name="url" required></div>
    <div>Comment:<input type="text" name="comment" required></div>

Form.get_initial_for_field(field, field_name)

Renvoie les données initiales d’un champ de formulaire. Il récupère les données de `Form.initial` s’il y en a, sinon il recherche dans `Field.initial`. Les valeurs exécutables sont évaluées.

Il est recommandé de privilégier `BoundField.initial` par rapport à `get_initial_for_field()` car l’interface de BoundField.initial` est plus simple. De plus, au contraire de `get_initial_for_field()`, `BoundField.initial` place ses valeurs en cache. C’est particulièrement utile lorsque les valeurs initiales sont exécutables et que leur résultat peut varier (par ex. `datetime.now` or `uuid.uuid4`) :

    >>> import uuid
    >>> class UUIDCommentForm(CommentForm):
    ...     identifier = forms.UUIDField(initial=uuid.uuid4)
    ...
    >>> f = UUIDCommentForm()
    >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
    UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
    >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
    UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
    >>> # Using BoundField.initial, for comparison
    >>> f["identifier"].initial
    UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
    >>> f["identifier"].initial
    UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')

## Contrôle des données de formulaires modifiées

Form.has_changed()

Lorsque vous avez besoin de savoir quelles données de formulaire ont été modifiées en référence aux données initiales, utilisez la méthode `has_changed()` du formulaire.

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data, initial=data)
    >>> f.has_changed()
    False

Lorsque le formulaire est envoyé, il est reconstruit et les données d’origine sont fournies afin que la comparaison puisse être faite :

    >>> f = ContactForm(request.POST, initial=data)
    >>> f.has_changed()
    True

`has_changed()` renvoie `True` si les données de `request.POST` diffèrent de celles qui ont été fournies dans `initial`, sinon elle renvoie `False`. Le résultat est produit en appelant `Field.has_changed()` pour chaque champ du formulaire.

Form.changed_data

L’attribut `changed_data` renvoie une liste des noms de champs dont les valeurs dans les données liées au formulaire (habituellement `request.POST`) diffèrent de celles fournies initialement dans `initial`. La liste renvoyée est vide si les données sont parfaitement identiques.

    >>> f = ContactForm(request.POST, initial=data)
    >>> f.changed_data
    ['subject', 'message']

## Accès aux champs depuis le formulaire

Form.fields

Vous pouvez accéder aux champs d’une instance de `Form` depuis son attribut `fields`:

    >>> for row in f.fields.values():
    ...     print(row)
    ...
    <django.forms.fields.CharField object at 0x7ffaac632510>
    <django.forms.fields.URLField object at 0x7ffaac632f90>
    <django.forms.fields.CharField object at 0x7ffaac3aa050>
    >>> f.fields["name"]
    <django.forms.fields.CharField object at 0x7ffaac6324d0>

Vous pouvez modifier le champ et la classe `BoundField` d’une instance `Form` pour changer la façon dont il sera affiché dans le formulaire :

    >>> f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
    >>> f["subject"].label = "Topic"
    >>> f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

Faites attention de ne pas modifier l’attribut `base_fields` car cette modification influencerait toutes les instances `ContactForm` suivantes à l’intérieur du même processus Python :

    >>> f.base_fields["subject"].label_suffix = "?"
    >>> another_f = ContactForm(auto_id=False)
    >>> another_f.as_div().split("</div>")[0]
    '<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

## Accès aux données « nettoyées »

Form.cleaned_data

Chaque champ d’une classe `Form` a non seulement la responsabilité de valider ses données, mais aussi de les « nettoyer », c’est-à-dire les normaliser dans un format cohérent. C’est une fonction bien utile, parce que cela permet de saisir les données d’un champ de plusieurs manières, tout en conservant une cohérence au niveau de la donnée résultante.

Par exemple, `DateField` normalise les saisies en un objet Python `datetime.date`. Que le contenu transmis soit une chaîne au format `'1994-07-15'`, un objet `datetime.date` ou un autre format encore, `DateField` transformera toujours ce contenu en objet `datetime.date`, pour autant qu’il soit valide.

Après avoir créé une instance de `Form` avec un jeu de données et l’avoir validé, il est possible d’accéder aux données nettoyées par son attribut `cleaned_data`:

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data
    {'subject': 'hello', 'message': 'Hi there', 'contact_email': 'foo@example.com', 'urgent': True}

Notez que tout champ basé sur du texte, tel que `CharField` ou `EmailField`, nettoie toujours le contenu saisi pour en faire une chaîne de caractères. Nous aborderons les implications du codage plus loin dans ce document.

Si vos données ne sont pas toutes valides, le dictionnaire `cleaned_data` ne contient que les champs valides :

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "contact_email": "invalid email address",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    False
    >>> f.cleaned_data
    {'message': 'Hi there', 'urgent': True}

`cleaned_data` ne contient toujours que des clés correspondant à des champs définis dans le formulaire, même si vous lui transmettez des données supplémentaires lors de la création du formulaire. Dans cet exemple, nous transmettons des données de champs supplémentaires au constructeur de `ContactForm`, mais `cleaned_data` ne contient que les données correspondant aux champs du formulaire :

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ...     "extra_field_1": "foo",
    ...     "extra_field_2": "bar",
    ...     "extra_field_3": "baz",
    ... }
    >>> f = ContactForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data  # Doesn't contain extra_field_1, etc.
    {'subject': 'hello', 'message': 'Hi there', 'contact_email': 'foo@example.com', 'urgent': True}

When the `Form` is valid, `cleaned_data` will include a key and value for all its fields, even if the data didn’t include a value for some optional fields. In this example, the data dictionary doesn’t include a value for the `nickname` field, but `cleaned_data` includes it, with an empty value:

    >>> from django import forms
    >>> class OptionalPersonForm(forms.Form):
    ...     first_name = forms.CharField()
    ...     last_name = forms.CharField()
    ...     nickname = forms.CharField(required=False)
    ...
    >>> data = {"first_name": "John", "last_name": "Lennon"}
    >>> f = OptionalPersonForm(data)
    >>> f.is_valid()
    True
    >>> f.cleaned_data
    {'first_name': 'John', 'last_name': 'Lennon', 'nickname': ''}

In this above example, the `cleaned_data` value for `nickname` is set to an empty string, because `nickname` is `CharField`, and `CharField`s treat empty values as an empty string. Each field type knows what its « blank » value is – e.g., for `DateField`, it’s `None` instead of the empty string. For full details on each field’s behavior in this case, see the « Empty value » note for each field in the Classes de champs Field intégrées section below.

Il est possible d’écrire du code pour effectuer la validation de certains champs de formulaires (en fonction de leur nom) ou pour le formulaire entier (prenant en compte la combinaison de différents champs). Vous trouverez davantage d’informations à ce sujet dans La validation de formulaires et de champs.

## Affichage des formulaires en HTML

La seconde tâche d’un objet `Form` est de s’afficher lui-même au format HTML. Pour faire cela, affichez-le avec `print`:

    >>> f = ContactForm()
    >>> print(f)
    <div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject"></div>
    <div><label for="id_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_message"></textarea></div>
    <div><label for="id_contact_email">Contact email:</label><input type="email" name="contact_email" maxlength="320" required id="id_contact_email"></div>
    <div><label for="id_urgent">Urgent:</label><input type="checkbox" name="urgent" id="id_urgent"></div>

Si le formulaire est lié à des données, le résultat HTML contiendra ces données comme il se doit. Par exemple, si un champ est représenté par un composant `<input type="text">`, les données figureront dans l’attribut `value`. Si un champ est représenté par un composant `<input type="checkbox">`, le HTML produit contiendra `checked` le cas échéant :

    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> f = ContactForm(data)
    >>> print(f)
    <div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
    <div><label for="id_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_message">Hi there</textarea></div>
    <div><label for="id_contact_email">Contact email:</label><input type="email" name="contact_email" value="foo@example.com" maxlength="320" required id="id_contact_email"></div>
    <div><label for="id_urgent">Urgent:</label><input type="checkbox" name="urgent" id="id_urgent" checked></div>

Cette production par défaut enveloppe chaque champ dans une `<div>`. À relever :

- Pour des raisons d’agilité, le résultat ne contient pas les balises `<form>` et `</form>`, ni la balise `<input type="submit">`. C’est à vous de les fournir.

- Chaque type de champ possède une représentation HTML par défaut. `CharField` est représenté par `<input type="text">` et `EmailField` par `<input type="email">`. `BooleanField(null=False)` est représenté par `<input type="checkbox">`. Notez qu’il ne s’agit que de valeurs par défaut raisonnables ; il est possible de définir le code HTML produit par un champ spécifique en utilisant des composants, ce que nous expliquerons tout à l’heure.

- Le nom `name` HTML de chaque balise est directement dérivé de son nom d’attribut dans la classe `ContactForm`.

- The text label for each field – e.g. `'Subject:'`, `'Message:'` and `'Contact email:'` is generated from the field name by converting all underscores to spaces and upper-casing the first letter. Again, note these are merely sensible defaults; you can also specify labels manually.

- Chaque étiquette textuelle est intégrée dans une balise HTML `<label>` qui se réfère à son champ de formulaire par son attribut `id`. La valeur de celui-ci est générée en ajoutant le préfixe `'id_'` au nom du champ. Les attributs `id` et les balises `<label>` sont compris dans le HTML produit par défaut pour être conforme aux bonnes pratiques, mais vous pouvez modifier ce comportement.

- Le résultat utilise la syntaxe HTML5, avec l’en-tête `<!DOCTYPE html>`. Par exemple, les attributs booléens tels que `checked` sont préférés au style XHTML `checked='checked'`.

Même si la production comme `<div>` est le style par défaut quand on affiche un formulaire par `print`, il est possible de personnaliser ce résultat en utilisant votre propre gabarit de formulaire qui peut être défini pour tout le site, par formulaire ou par instance. Voir Gabarits de formulaire réutilisables.

### Rendu par défaut

Le rendu par défaut lorsque vous affichez un formulaire par `print` utilise les méthodes et attributs suivants.

#### `template_name`

Form.template_name

Le nom du gabarit produit si le formulaire est forcé à une chaîne, par ex. via `print(form)` ou dans un gabarit via `{{ form }}`.

Par défaut, une propriété renvoyant la valeur `form_template_name` du producteur. Vous pouvez la définir à un nom de gabarit afin de la surcharger pour une classe de formulaire particulière.

#### `render()`

Form.render(template_name=None, context=None, renderer=None)

La méthode de production est appelée par `__str__` ainsi que par les méthodes `Form.as_div()`, `Form.as_table()`, `Form.as_p()` et `Form.as_ul()`. Tous les arguments sont facultatifs et valent par défaut :

- `template_name`: `Form.template_name`

- `context`: la valeur renvoyée par `Form.get_context()`

- `renderer`: la valeur renvoyée par `Form.default_renderer`

En passant `template_name`, vous pouvez personnaliser le gabarit utilisé pour un seul appel.

#### `get_context()`

Form.get_context()

Renvoie le contexte de gabarit utilisé pour produire le formulaire.

Le contexte disponible est :

- `form`: le formulaire lié.

- `fields`: tous les champs liés, exceptés les champs cachés.

- `hidden_fields`: tous les champs liés cachés.

- `errors`: toutes les erreurs de formulaire non liées aux champs ou liées à des champs cachés.

#### `template_name_label`

Form.template_name_label

Le gabarit utilisé pour produire la balise `<label>` d’un champ, utilisé lors de l’appel à `BoundField.label_tag()`/`legend_tag()`. Ce gabarit peut être adapté pour chaque formulaire en surchargeant cet attribut ou plus généralement en surchargeant le gabarit par défaut, voir aussi Redéfinition des gabarits de formulaires intégrés.

### Styles de production

L’approche recommandée pour changer le style de production des formulaires est de définir un gabarit de formulaire personnalisé soit pour tout le site, par formulaire ou par instance. Voir Gabarits de formulaire réutilisables pour des exemples.

Les fonctions utilitaires suivantes sont fournies par rétrocompatibilité et sont des raccourcis appelant `Form.render()` et en lui passant une valeur `template_name` particulière.

Note

Parmi les styles de gabarits et de production que Django met à disposition, le style par défaut `as_div()` est recommandé par rapport aux versions `as_p()`, `as_table()` et `as_ul()`, car ce gabarit exploite les balises `<fieldset>` et `<legend>` pour grouper les composants «input» liés et facilite leur lecture en naviguant avec les lecteurs d’écran.

Chaque utilitaire lie une méthode de formulaire à un attribut donnant le nom de gabarit approprié.

#### `as_div()`

Form.template_name_div

Le gabarit utilisé par `as_div()`. Par défaut : `'django/forms/div.html'`.

Form.as_div()

`as_div()` produit le formulaire par une série de balises `<div>`, avec chaque `<div>` contenant un champ, tel que :

    >>> f = ContactForm()
    >>> f.as_div()

… gives HTML like:

    <div>
    <label for="id_subject">Subject:</label>
    <input type="text" name="subject" maxlength="100" required id="id_subject">
    </div>
    <div>
    <label for="id_message">Message:</label>
    <textarea name="message" cols="40" rows="10" required id="id_message"></textarea>
    </div>
    <div>
    <label for="id_contact_email">Contact email:</label>
    <input type="email" name="contact_email" required id="id_contact_email">
    </div>
    <div>
    <label for="id_urgent">Urgent:</label>
    <input type="checkbox" name="urgent" id="id_urgent">
    </div>

#### `as_p()`

Form.template_name_p

Le gabarit utilisé par `as_p()`. Par défaut : `'django/forms/p.html'`.

Form.as_p()

`as_p()` produit le formulaire par une série de balises `<p>`, chacune contenant un champ :

    >>> f = ContactForm()
    >>> f.as_p()

… gives HTML like:

    <p><label for="id_subject">Subject:</label> <input type="text" name="subject" maxlength="100" required id="id_subject"></p>
    <p><label for="id_message">Message:</label> <textarea name="message" cols="40" rows="10" required id="id_message"></textarea></p>
    <p><label for="id_contact_email">Contact email:</label> <input type="email" name="contact_email" maxlength="320" required id="id_contact_email"></p>
    <p><label for="id_urgent">Urgent:</label> <input type="checkbox" name="urgent" id="id_urgent"></p>

#### `as_ul()`

Form.template_name_ul

Le gabarit utilisé par `as_ul()`. Par défaut : `'django/forms/ul.html'`.

Form.as_ul()

`as_ul()` produit le formulaire par une série de balises `<li>`, chacune contenant un champ. Les balises `<ul>` et `</ul>` ne sont pas comprises, ce qui vous donne la flexibilité de définir vous-même des attributs à la balise `<ul>`:

    >>> f = ContactForm()
    >>> f.as_ul()

… gives HTML like:

    <li><label for="id_subject">Subject:</label> <input type="text" name="subject" maxlength="100" required id="id_subject"></li>
    <li><label for="id_message">Message:</label> <textarea name="message" cols="40" rows="10" required id="id_message"></textarea></li>
    <li><label for="id_contact_email">Contact email:</label> <input type="email" name="contact_email" maxlength="320" required id="id_contact_email"></li>
    <li><label for="id_urgent">Urgent:</label> <input type="checkbox" name="urgent" id="id_urgent"></li>

#### `as_table()`

Form.template_name_table

Le gabarit utilisé par `as_table()`. Par défaut : `'django/forms/table.html'`.

Form.as_table()

`as_table()` produit le formulaire sous forme de `<table>` HTML :

    >>> f = ContactForm()
    >>> f.as_table()

… gives HTML like:

    <tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" maxlength="100" required id="id_subject"></td></tr>
    <tr><th><label for="id_message">Message:</label></th><td><textarea name="message" cols="40" rows="10" required id="id_message"></textarea></td></tr>
    <tr><th><label for="id_contact_email">Contact email:</label></th><td><input type="email" name="contact_email" maxlength="320" required id="id_contact_email"></td></tr>
    <tr><th><label for="id_urgent">Urgent:</label></th><td><input type="checkbox" name="urgent" id="id_urgent"></td></tr>

### Ajout de styles aux lignes de formulaire obligatoires ou erronées

Form.error_css_class

Form.required_css_class

Il est assez fréquent de devoir définir des styles particuliers s’appliquant aux lignes et champs de formulaire qui sont obligatoires ou qui contiennent des erreurs. Par exemple, on pourrait afficher en gras les lignes de formulaire obligatoires et afficher les erreurs en rouge.

La classe `Form` offre plusieurs points d’entrée permettant d’ajouter des attributs `class` aux lignes obligatoires ou aux lignes avec des erreurs : complétez les attributs `Form.error_css_class` et `Form.required_css_class`

    from django import forms

    class ContactForm(forms.Form):
        error_css_class = "error"
        required_css_class = "required"

        # ... and the rest of your fields here

Après avoir fait cela, les classes `"error"` et `"required"` seront attribuées aux lignes correspondantes. Le code HTML ressemblera à quelque chose comme :

    >>> f = ContactForm(data)
    >>> print(f)
    <div class="required"><label for="id_subject" class="required">Subject:</label> ...
    <div class="required"><label for="id_message" class="required">Message:</label> ...
    <div class="required"><label for="id_contact_email" class="required">Contact email:</label> ...
    <div><label for="id_urgent">Urgent:</label> ...
    >>> f["subject"].label_tag()
    <label class="required" for="id_subject">Subject:</label>
    >>> f["subject"].legend_tag()
    <legend class="required" for="id_subject">Subject:</legend>
    >>> f["subject"].label_tag(attrs={"class": "foo"})
    <label for="id_subject" class="foo required">Subject:</label>
    >>> f["subject"].legend_tag(attrs={"class": "foo"})
    <legend for="id_subject" class="foo required">Subject:</legend>

Il est possible de modifier davantage le rendu des lignes de formulaires en utilisant un BoundField personnalisé.

### Configuration des attributs `id` et des balises `<label>` dans le code HTML des formulaires

Form.auto_id

Par défaut, les méthodes de rendu HTML des formulaires comprennent :

- Les attributs HTML `id` des éléments de formulaire.

- Les balises `<label>` autour des étiquettes de champ. Une balise HTML `<label>` détermine quel texte descriptif est associé à un élément de formulaire. Cette petite amélioration rend les formulaires plus conviviaux et mieux adaptés aux techniques d’accessibilité. Il est recommandé de toujours utiliser des balises `<label>`.

Les valeurs d’attribut `id` sont générées en préfixant les noms de champ de formulaire par `id_`. Ce mécanisme peut cependant être configuré si vous souhaitez modifier la convention `id` ou supprimer complètement les attributs HTML `id` ou les balises `<label>`.

Utilisez le paramètre `auto_id` du constructeur de `Form` pour contrôler le comportement `id` et `label`. Ce paramètre doit valoir `True`, `False` ou contenir une chaîne.

Si `auto_id` vaut `False`, le rendu HTML du formulaire ne contiendra par de balises `<label>` ni d’attributs `id`:

    >>> f = ContactForm(auto_id=False)
    >>> print(f)
    <div>Subject:<input type="text" name="subject" maxlength="100" required></div>
    <div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
    <div>Contact email:<input type="email" name="contact_email" required></div>
    <div>Urgent:<input type="checkbox" name="urgent"></div>

Si `auto_id` est défini à `True`, le rendu HTML du formulaire contiendra des balises `<label>` et utilisera le nom du champ comme identifiant `id` pour chaque champ de formulaire :

    >>> f = ContactForm(auto_id=True)
    >>> print(f)
    <div><label for="subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="subject"></div>
    <div><label for="message">Message:</label><textarea name="message" cols="40" rows="10" required id="message"></textarea></div>
    <div><label for="contact_email">Contact email:</label><input type="email" name="contact_email" required id="contact_email"></div>
    <div><label for="urgent">Urgent:</label><input type="checkbox" name="urgent" id="urgent"></div>

Si `auto_id` est défini à une chaîne contenant le caractère de format `'%s'`, le rendu HTML du formulaire contiendra des balises `<label>` et produira des attributs `id` en fonction de la chaîne de format. Par exemple, compte tenu d’une chaîne de format `'champ_%s'`, l’attribut `id` d’un champ nommé``sujet`` sera `'champ_sujet'`. En poursuivant notre exemple :

    >>> f = ContactForm(auto_id="id_for_%s")
    >>> print(f)
    <div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_contact_email">Contact email:</label><input type="email" name="contact_email" required id="id_for_contact_email"></div>
    <div><label for="id_for_urgent">Urgent:</label><input type="checkbox" name="urgent" id="id_for_urgent"></div>

Si `auto_id` est défini à toute autre valeur évaluée à la valeur « vrai », comme par exemple une chaîne ne contenant pas de `%s`, la bibliothèque va considérer que `auto_id` vaut `True`.

Par défaut, `auto_id` contient la valeur `'id_%s'`.

Form.label_suffix

Une chaîne traduisible (en anglais, la valeur par défaut est deux-points (`:`)) qui sera ajoutée à chaque nom d’étiquette lors du rendu HTML d’un formulaire.

Il est possible de personnaliser ce caractère ou de l’omettre entièrement en utilisant le paramètre `label_suffix`:

    >>> f = ContactForm(auto_id="id_for_%s", label_suffix="")
    >>> print(f)
    <div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_contact_email">Contact email</label><input type="email" name="contact_email" required id="id_for_contact_email"></div>
    <div><label for="id_for_urgent">Urgent</label><input type="checkbox" name="urgent" id="id_for_urgent"></div>
    >>> f = ContactForm(auto_id="id_for_%s", label_suffix=" ->")
    >>> print(f)
    <div><label for="id_for_subject">Subject -&gt;</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
    <div><label for="id_for_message">Message -&gt;</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
    <div><label for="id_for_contact_email">Contact email -&gt;</label><input type="email" name="contact_email" required id="id_for_contact_email"></div>
    <div><label for="id_for_urgent">Urgent -&gt;</label><input type="checkbox" name="urgent" id="id_for_urgent"></div>

Notez que le suffixe d’étiquette n’est ajouté que si le dernier caractère de l’étiquette n’est pas un caractère de ponctuation (en anglais, il s’agit de `.`, `!`, `?` ou `:`).

Les champs peuvent aussi définir leur propre `label_suffix`. Cette définition a la priorité sur `Form.label_suffix`. Le suffixe peut aussi être surchargé au cours de l’exécution en utilisant le paramètre `label_suffix` de `label_tag()`/`legend_tag()`.

Form.use_required_attribute

Si défini à `True` (par défaut), les champs de formulaire obligatoires possèdent l’attribut HTML `required`.

Les formulaires groupés créent leurs formulaires avec `use_required_attribute=False` pour éviter la validation incorrecte des navigateurs lors de l’ajout ou de la suppression de formulaires dans des formulaires groupés.

### Configuration du rendu des composants de formulaires

Form.default_renderer

Indique le moteur de rendu à utiliser pour le formulaire. Vaut `None` par défaut, ce qui signifie que le moteur de rendu par défaut défini dans le réglage `FORM_RENDERER` sera utilisé.

Vous pouvez le définir comme attribut de classe lors de la déclaration du formulaire ou utiliser le paramètre `renderer` de `Form.__init__()`. Par exemple :

    from django import forms

    class MyForm(forms.Form):
        default_renderer = MyRenderer()

ou :

    form = MyForm(renderer=MyRenderer())

### Notes sur le tri des champs

In the `as_p()`, `as_ul()` and `as_table()` shortcuts, the fields are displayed in the order in which you define them in your form class. For example, in the `ContactForm` example, the fields are defined in the order `subject`, `message`, `contact_email`, `urgent`. To reorder the HTML output, change the order in which those fields are listed in the class.

Il existe plusieurs autres manières de personnaliser cet ordre :

Form.field_order

Par défaut, `Form.field_order=None`, ce qui conserve l’ordre dans lequel les champs sont définis dans la classe de formulaire. Si `field_order` est une liste de noms de champs, les champs sont ordonnés en fonction de cette liste et les champs restants sont ajoutés selon l’ordre par défaut. Les noms de champs de la liste qui sont inconnus sont ignorés. Cela permet de désactiver un champ dans une sous-classe en le définissant à `None` sans avoir à redéfinir l’ordre.

Il est également possible d’utiliser le paramètre `Form.field_order` d’une classe `Form` pour remplacer l’ordre des champs. Si un formulaire `Form` définit `field_order` et que `field_order` est inclus lors de l’instanciation de `Form`, c’est ce dernier `field_order` qui a la priorité.

Form.order_fields(field_order)

Vous pouvez réorganiser les champs à tout moment en utilisant `order_fields()` avec une liste de noms de champs comme dans `field_order`.

### Affichage des erreurs

Lorsque vous affichez un objet `Form` lié à des données, le fait de l’afficher va automatiquement procéder à la validation du formulaire s’il ne l’a pas encore été, et le résultat HTML contiendra les erreurs de validation sous forme d’une section `<ul class="errorlist">`.

Le code suivant :

    >>> data = {
    ...     "subject": "",
    ...     "message": "Hi there",
    ...     "contact_email": "invalid email address",
    ...     "urgent": True,
    ... }
    >>> ContactForm(data).as_div()

… gives HTML like:

    <div>
      <label for="id_subject">Subject:</label>
      <ul class="errorlist" id="id_subject_error"><li>This field is required.</li></ul>
      <input type="text" name="subject" maxlength="100" required aria-invalid="true" aria-describedby="id_subject_error" id="id_subject">
    </div>
    <div>
      <label for="id_message">Message:</label>
      <textarea name="message" cols="40" rows="10" required id="id_message">Hi there</textarea>
    </div>
    <div>
      <label for="id_contact_email">Contact email:</label>
      <ul class="errorlist" id="id_contact_email_error"><li>Enter a valid email address.</li></ul>
      <input type="email" name="contact_email" value="invalid email address" maxlength="320" required aria-invalid="true" aria-describedby="id_contact_email_error" id="id_contact_email">
    </div>
    <div>
        <label for="id_urgent">Urgent:</label>
        <input type="checkbox" name="urgent" id="id_urgent" checked>
    </div>

Les gabarits par défaut des formulaires associent les erreurs de validation à leur composant en utilisant l’attribut HTML `aria-describedby` lorsque le champ possède une valeur `auto_id` et pas de valeur `aria-describedby` personnalisée. Si une valeur `aria-describedby` personnalisée est présente dans la définition du composant, cela écrasera la valeur par défaut.

Si le composant est produit dans un `<fieldset>`, alors `aria-describedby` est ajouté à cet élément, sinon il est ajouté à l’élément HTML du composant (par ex. `<input>`).

### Personnalisation du format de la liste d’erreurs

class ErrorList(initlist=None, error_class=None, renderer=None, field_id=None)

  Par défaut, les formulaires utilisent `django.forms.utils.ErrorList` pour mettre en forme les erreurs de validation. `ErrorList` est un objet de type liste où `initlist` est la liste des erreurs. De plus, cette classe possède les attributs et méthodes suivantes.

  error_class

    Les classes CSS à utiliser lors de la production de la liste des erreurs. Les éventuelles classes indiquées sont ajoutées à la classe `errorlist` par défaut.

  renderer

    Indique le moteur de rendu à utiliser pour `ErrorList`. Vaut `None` par défaut, ce qui signifie que le moteur de rendu par défaut défini dans le réglage `FORM_RENDERER` sera utilisé.

  field_id

    L’identifiant du champ auquel l’erreur se réfère. Cela permet d’ajouter un attribut HTML `id` dans le gabarit d’erreur et aide à associer les erreurs avec leur champ. Le gabarit par défaut utilise le format `id="{{ field_id }}_error"` et une valeur est fournie par `Form.add_error()` en utilisant la valeur `auto_id` du champ.

  template_name

    Le nom du gabarit utilisé lors de l’appel à `__str__` ou `render()`. Par défaut, il s’agit de `'django/forms/errors/list/default.html'` qui redirige en réalité sur le gabarit `'ul.html'`.

  template_name_text

    Le nom du gabarit utilisé lors de l’appel à `as_text()`. Par défaut, il s’agit de `'django/forms/errors/list/test.html'`. Ce gabarit produit les erreurs sous forme de liste à puces.

  template_name_ul

    Le nom du gabarit utilisé lors de l’appel à `as_ul()`. Par défaut, il s’agit de `'django/forms/errors/list/ul.html'`. Ce gabarit produit les erreurs dans des balises `<li>` enveloppées par `<ul>` avec les classes CSS telles que définies par `error_class`.

  get_context()

    Renvoie le contexte pour la production des erreurs dans un gabarit.

    Le contexte disponible est :

    - `errors` : une liste des erreurs.

    - `error_class` : une chaîne de classes CSS.

  render(template_name=None, context=None, renderer=None)

    La méthode `render` est appelée par `__str__` en plus de la méthode `as_ul()`.

    Tous les arguments sont facultatifs et contiennent par défaut :

    - `template_name`: la valeur renvoyée par `template_name`

    - `context`: la valeur renvoyée par `get_context()`

    - `renderer`: la valeur renvoyée par `renderer`

  as_text()

    Effectue le rendu de la liste des erreurs en utilisant le gabarit défini par `template_name_text`.

  as_ul()

    Effectue le rendu de la liste des erreurs en utilisant le gabarit défini par `template_name_ul`.

  Si vous souhaitez personnaliser le rendu des erreurs, cela peut se faire en surchargeant l’attribut `template_name` ou plus généralement en surchargeant le gabarit par défaut, voir aussi Redéfinition des gabarits de formulaires intégrés.

## Un affichage plus fin

Les méthodes `as_p()`, `as_ul()` et `as_table()` sont des raccourcis, ce ne sont pas les seules façons d’afficher une objet formulaire.

class BoundField

  Utilisé pour afficher en HTML un champ unique d’une instance de `Form` ou pour accéder à ses attributs.

  La méthode `__str__()` de cet objet affiche le code HTML du champ.

  Vous pouvez utiliser `Form.bound_field_class` et `Field.bound_field_class` pour indiquer une classe `BoundField` différente, respectivement par formulaire ou par champ.

  Voir Personnalisation de BoundField pour des exemples de surcharge de `BoundField`.

Pour récupérer un seul `BoundField`, employez la syntaxe de consultation de dictionnaire sur le formulaire en utilisant le nom du champ comme clé :

    >>> form = ContactForm()
    >>> print(form["subject"])
    <input type="text" name="subject" maxlength="100" required id="id_subject">

Pour obtenir tous les objets `BoundField`, faites une boucle sur le formulaire :

    >>> form = ContactForm()
    >>> for boundfield in form:
    ...     print(boundfield)
    ...
    <input type="text" name="subject" maxlength="100" required id="id_subject">
    <textarea name="message" cols="40" rows="10" required id="id_message"></textarea>
    <input type="email" name="contact_email" maxlength="320" required id="id_contact_email">
    <input type="checkbox" name="urgent" id="id_urgent">

Le résultat HTML spécifique de chaque champ respecte le réglage `auto_id` de l’objet formulaire :

    >>> f = ContactForm(auto_id=False)
    >>> print(f["message"])
    <textarea name="message" cols="40" rows="10" required></textarea>
    >>> f = ContactForm(auto_id="id_%s")
    >>> print(f["message"])
    <textarea name="message" cols="40" rows="10" required id="id_message"></textarea>

### Attributs de `BoundField`

BoundField.aria_describedby

  Renvoie une référence `aria-describedby` pour associer un champ avec sont texte d’aide et ses erreurs. Renvoie `None` si `aria-describedby` est défini dans `Widget.attrs`, pour préserver l’attribut défini par l’utilisateur lors du rendu du formulaire.

BoundField.auto_id

  L’attribut HTML ID de cet objet `BoundField`. Renvoie une chaîne vide si `Form.auto_id` vaut `False`.

BoundField.data

  Cette propriété renvoie les données de cet objet `BoundField` extraites par la méthode de composant `value_from_datadict()`, ou `None` si elle n’a pas été indiquée :

      >>> unbound_form = ContactForm()
      >>> print(unbound_form["subject"].data)
      None
      >>> bound_form = ContactForm(data={"subject": "My Subject"})
      >>> print(bound_form["subject"].data)
      My Subject

BoundField.errors

  Un objet apparenté à une liste qui s’affiche par une section `<ul class="errorlist">` lorsqu’il est affiché en HTML :

      >>> data = {"subject": "hi", "message": "", "contact_email": "", "urgent": ""}
      >>> f = ContactForm(data, auto_id=False)
      >>> print(f["message"])
      <input type="text" name="message" required aria-invalid="true">
      >>> f["message"].errors
      ['This field is required.']
      >>> print(f["message"].errors)
      <ul class="errorlist"><li>This field is required.</li></ul>
      >>> f["subject"].errors
      []
      >>> print(f["subject"].errors)

      >>> str(f["subject"].errors)
      ''

  Lors du rendu d’un champ avec des erreurs, l’attribut `aria-invalid="true"` sera défini pour le composant du champ pour indiquer aux lecteurs d’écran qu’il y a une erreur.

BoundField.field

  L’instance `Field` de la classe de formulaire que cet objet `BoundField` adapte.

BoundField.form

  L’instance `Form` à laquelle est lié cet objet `BoundField`.

BoundField.help_text

  Le texte d’aide `help_text` du champ.

BoundField.html_name

  Le nom qui sera utilisé dans l’attribut `name` du code HTML du composant. Il prend en compte la valeur `prefix` du formulaire.

BoundField.id_for_label

  Utilisez cette propriété pour produire l’identifiant de ce champ. Par exemple, si vous construisez manuellement une balise `<label>` dans un gabarit (sans tenir compte que `label_tag()`/`legend_tag()` le ferait très bien à votre place) :

      <label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}

  Par défaut, il s’agira du nom du champ préfixé par `id_` ( »`id_my_field` » dans l’exemple ci-dessus). Il est possible de modifier cet identifiant en renseignant `attrs` pour le composant du champ. Par exemple, en définissant un champ comme ceci :

      my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))

  et en utilisant le gabarit ci-dessus, le résultat affiché donnera quelque chose comme :

      <label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>

BoundField.initial

  Utilisez `BoundField.initial` pour obtenir les valeurs initiales d’un champ de formulaire. Les données sont obtenues de `Form.initial` s’il y en a, sinon il recherche dans `Field.initial`. Les valeurs exécutables sont évaluées. Voir Valeurs initiales de formulaires pour des exemples.

  `BoundField.initial` met en cache sa valeur calculée, ce qui est particulièrement utile lorsque les valeurs sont des résultats variables de fonctions exécutables (par ex. `datetime.now` ou `uuid.uuid4`) :

      >>> from datetime import datetime
      >>> class DatedCommentForm(CommentForm):
      ...     created = forms.DateTimeField(initial=datetime.now)
      ...
      >>> f = DatedCommentForm()
      >>> f["created"].initial
      datetime.datetime(2021, 7, 27, 9, 5, 54)
      >>> f["created"].initial
      datetime.datetime(2021, 7, 27, 9, 5, 54)

  Il est recommandé de privilégier attr:BoundField.initial par rapport à `get_initial_for_field()`.

BoundField.is_hidden

  Renvoie `True` si le composant de cet objet `BoundField` est invisible.

BoundField.label

  L’étiquette `label` du champ. Utilisée dans les méthodes `label_tag()`/`legend_tag()`.

BoundField.name

  Le nom de ce champ dans le formulaire :

      >>> f = ContactForm()
      >>> print(f["subject"].name)
      subject
      >>> print(f["message"].name)
      message

BoundField.template_name

  Le nom du gabarit produit avec `BoundField.as_field_group()`.

  Une propriété renvoyant la valeur de `template_name`, si elle est définie, ou de `field_template_name` dans le cas contraire.

BoundField.use_fieldset

  Renvoie la valeur de l’attribut `use_fieldset` du composant de ce `BoundField`.

BoundField.widget_type

  Renvoie le nom de classe en minuscules du composant du champ enveloppé, sans un éventuel suffixe `input` ou `widget`. Cela peut être utilisé lors de la construction de formulaires lorsque la disposition est dépendante du type de composant. Par exemple :

      {% for field in form %}
          {% if field.widget_type == 'checkbox' %}
              # render one way
          {% else %}
              # render another way
          {% endif %}
      {% endfor %}

### Méthodes de `BoundField`

BoundField.as_field_group()

  Produit le champ avec `BoundField.render()` avec des valeurs par défaut, ce qui produit le champ `BoundField`, y compris son étiquette, son texte d’aide et d’éventuelles erreurs sur la base du gabarit `template_name` si défini ou sinon `field_template_name`.

BoundField.as_hidden(attrs=None, **kwargs)

  Renvoie une chaîne HTML pour représenter le champ sous forme de `<input type="hidden">`.

  `**kwargs` est retransmis à `as_widget()`.

  Cette méthode est essentiellement utilisée en interne. Il est préférable d’utiliser plutôt un composant (`widget`).

BoundField.as_widget(widget=None, attrs=None, only_initial=False)

  Produit l’affichage du champ en s’appuyant sur le composant `widget` transmis, et en ajoutant d’éventuels attributs HTML transmis dans `attrs`. Si aucun composant n’est fourni, c’est le composant par défaut du champ qui sera utilisé.

  `only_initial` est utilisé en interne par Django et ne devrait pas être défini explicitement.

BoundField.css_classes(extra_classes=None)

  Lorsque vous utilisez les raccourcis d’affichage de Django, les classes CSS sont utilisées pour indiquer les champs de formulaire obligatoires ou les champs contenant des erreurs. Si vous affichez manuellement les champs de formulaire, ces classes CSS sont disponibles par la méthode `css_classes`:

      >>> f = ContactForm(data={"message": ""})
      >>> f["message"].css_classes()
      'required'

  Si vous souhaitez fournir des classes supplémentaires en plus des classes liées aux erreurs et aux champs obligatoires, il est possible d’indiquer ces classes en paramètre :

      >>> f = ContactForm(data={"message": ""})
      >>> f["message"].css_classes("foo bar")
      'foo bar required'

BoundField.get_context()

  Renvoie le contexte de gabarit pour le rendu du champ. Dans le contexte disponible, `field` est l’instance du champ lié (`BoundField`).

BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)

  Effectue le rendu d’une balise `label` d’un champ de formulaire en utilisant le gabarit défini par `Form.template_name_label`.

  Le contexte disponible est :

  - `field`: l’instance du champ lié `BoundField` correspondant.

  - `contents`: par défaut, une chaîne concaténant attr:BoundField.label et `Form.label_suffix` (o `Field.label_suffix`, si défini).

  - `attrs`: un `dict` contenant `for`, `Form.required_css_class` et `id`. `id` est généré par les attributs `attrs` du composant du champ ou par `BoundField.auto_id`. Des attributs supplémentaires peuvent être fournis par l’argument `attrs`.

  - `use_tag`: une valeur booléenne qui vaut `True` si l’étiquette possède un `id`. Si `False`, le gabarit par défaut omet la balise.

  - `tag`: une chaîne facultative pour personnaliser la balise, contient `label` par défaut.

  Astuce

  Dans votre gabarit, `field` est l’instance de champ `BoundField`. C’est ainsi que l’appel à `field.field` fait référence à `BoundField.field` qui est le champ déclaré, par ex. `forms.CharField`.

  Pour afficher séparément la balise `label` d’un champ de formulaire, on peut appeler sa méthode `label_tag()`:

      >>> f = ContactForm(data={"message": ""})
      >>> print(f["message"].label_tag())
      <label for="id_message">Message:</label>

  Si vous souhaitez personnaliser le rendu, cela peut se faire en surchargeant l’attribut `Form.template_name_label` ou plus généralement en surchargeant le gabarit par défaut, voir aussi Redéfinition des gabarits de formulaires intégrés.

BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)

  Appelle `label_tag()` avec `tag='legend'` pour produire l’étiquette avec des balises `<legend>`. C’est utile lors de la production de composants boutons radios et cases à cocher mutliples où `<legend>` peut être plus adéquat qu’une balise `<label>`.

BoundField.render(template_name=None, context=None, renderer=None)

  La méthode de rendu est appelée par `as_field_group`. Tous les arguments sont facultatifs et leur valeur par défaut est :

  - `template_name`: `BoundField.template_name`

  - `context`: la valeur renvoyée par `BoundField.get_context()`

  - `renderer`: la valeur renvoyée par `Form.default_renderer`

  En passant `template_name`, vous pouvez personnaliser le gabarit utilisé pour un seul appel.

BoundField.value()

  Utilisez cette méthode pour afficher la valeur brute d’un champ telle qu’elle serait contenue dans un composant `Widget`:

      >>> initial = {"subject": "welcome"}
      >>> unbound_form = ContactForm(initial=initial)
      >>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial)
      >>> print(unbound_form["subject"].value())
      welcome
      >>> print(bound_form["subject"].value())
      hi

## Personnalisation de `BoundField`

Form.bound_field_class

Définit une classe `BoundField` personnalisée à utiliser lors du rendu du formulaire. Cet attribut a la priorité sur une éventuelle valeur `BaseRenderer.bound_field_class` (ou qu’une valeur `FORM_RENDERER` personnalisée) au niveau du projet, mais elle peut elle-même être remplacée par l’attribut `Field.bound_field_class` défini au niveau du champ.

Si elle n’est pas définie comme variable de classe, `bound_field_class` peut être définie via l’argument `bound_field_class` du constructeur de `Form` ou de `Field`.

Pour des raisons de compatibilité, un champ de formulaire personnalisé peut tout de même surcharger `Field.get_bound_field()` pour obtenir une classe personnalisée, même si les options précédemment décrites sont préférées.

Si vous avez besoin d’accéder à certaines informations supplémentaires au sujet d’un champ de formulaire dans un gabarit et que l’usage d’une sous-classe de `Field` n’est pas suffisant, il peut être souhaitable d’utiliser une classe `BoundField` personnalisée.

Par exemple, si vous avez un champ `GPSCoordinatesField` et que vous souhaitez pouvoir accéder à des informations supplémentaires sur les coordonnées dans un gabarit, cela pourrait être implémenté de cette façon :

    class GPSCoordinatesBoundField(BoundField):
        @property
        def country(self):
            """
            Return the country the coordinates lie in or None if it can't be
            determined.
            """
            value = self.value()
            if value:
                return get_country_from_coordinates(value)
            else:
                return None

    class GPSCoordinatesField(Field):
        bound_field_class = GPSCoordinatesBoundField

Il est maintenant possible d’accéder au pays dans un gabarit avec `{{ form.coordinates.country }}`.

Il peut également être utile de pouvoir personnaliser le rendu du gabarit de champ de formulaire par défaut. Par exemple, vous pouvez surcharger `BoundField.label_tag()` pour ajouter une classe personnalisée :

    class StyledLabelBoundField(BoundField):
        def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None):
            attrs = attrs or {}
            attrs["class"] = "wide"
            return super().label_tag(contents, attrs, label_suffix, tag)

    class UserForm(forms.Form):
        bound_field_class = StyledLabelBoundField
        name = CharField()

Cela donnerait le rendu de formulaire par défaut suivant :

    >>> f = UserForm()
    >>> print(f["name"].label_tag)
    <label for="id_name" class="wide">Name:</label>

Pour ajouter une classe CSS à l’élément HTML englobant de tous les champs, un champ `BoundField` peut être surchargé pour renvoyer un ensemble de classes CSS différentes :

    class WrappedBoundField(BoundField):
        def css_classes(self, extra_classes=None):
            parent_css_classes = super().css_classes(extra_classes)
            return f"field-class {parent_css_classes}".strip()

    class UserForm(forms.Form):
        bound_field_class = WrappedBoundField
        name = CharField()

Cela produirait le rendu de formulaire suivant :

    >>> f = UserForm()
    >>> print(f)
    <div class="field-class"><label for="id_name">Name:</label><input type="text" name="name" required id="id_name"></div>

Il est également possible de surcharger la classe `BoundField` au niveau du projet, une version personnalisée de `FORM_RENDERER` peut définir `BaseRenderer.bound_field_class`:

`mysite/renderers.py`

    from django.forms.renderers import DjangoTemplates

    from .forms import CustomBoundField

    class CustomRenderer(DjangoTemplates):
        bound_field_class = CustomBoundField

`settings.py`

    FORM_RENDERER = "mysite.renderers.CustomRenderer"

## Liaison de fichiers téléversés avec un formulaire

Lorsqu’on a affaire à des champs de formulaire de type `FileField` ou `ImageField`, les choses se compliquent un peu plus.

Premièrement, pour pouvoir envoyer des fichiers, il est important que la balise `<form>` du formulaire définisse correctement son attribut `enctype` à `"multipart/form-data"`:

    <form enctype="multipart/form-data" method="post" action="/foo/">

Deuxièmement, au moment d’instancier le formulaire, il faut lier les données de type fichier. Ces données sont traitées de manière distincte des données habituelles de formulaire, ce qui fait que quand un formulaire contient un champ `FileField` ou `ImageField`, il doit recevoir un second paramètre au moment de faire la liaison entre le formulaire et les données. Ainsi, si nous étendons notre `ContactForm` pour qu’il contienne un champ `ImageField` nommé `mugshot`, nous devons lier les données de fichier contenant l’image `mugshot`:

    # Bound form with an image field
    >>> from django.core.files.uploadedfile import SimpleUploadedFile
    >>> data = {
    ...     "subject": "hello",
    ...     "message": "Hi there",
    ...     "contact_email": "foo@example.com",
    ...     "urgent": True,
    ... }
    >>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
    >>> f = ContactFormWithMugshot(data, file_data)

En pratique, vous allez généralement indiquer `request.FILES` comme source des données de fichier (comme pour `request.POST` représentant la source des données de formulaire) :

    # Bound form with an image field, data from the request
    >>> f = ContactFormWithMugshot(request.POST, request.FILES)

La construction d’un formulaire non lié ne change pas, il suffit d’omettre aussi bien les données de formulaire que les données de fichier :

    # Unbound form with an image field
    >>> f = ContactFormWithMugshot()

### Détection des formulaires composites

Form.is_multipart()

Si vous écrivez des vues ou des gabarits réutilisables, il peut arriver que l’on ne sache pas à l’avance si un formulaire est composite. La méthode `is_multipart()` indique si le formulaire nécessite un codage composite lors de son envoi :

    >>> f = ContactFormWithMugshot()
    >>> f.is_multipart()
    True

Voici un exemple de la façon d’utiliser cette méthode dans un gabarit :

    {% if form.is_multipart %}
        <form enctype="multipart/form-data" method="post" action="/foo/">
    {% else %}
        <form method="post" action="/foo/">
    {% endif %}
    {{ form }}
    </form>

## Formulaires et sous-classes

Si vous avez plusieurs classes `Form` dont les champs sont partagés, il est possible d’utiliser l’héritage pour éviter la redondance.

Lorsque vous héritez d’une classe `Form` personnalisée, la sous-classe résultante inclut tous les champs des ses classes parentes, suivis des champs définis dans la sous-classe.

In this example, `ContactFormWithDepartment` contains all the fields from `ContactForm`, plus an additional field, `department`. The `ContactForm` fields are ordered first:

    >>> class ContactFormWithDepartment(ContactForm):
    ...     department = forms.CharField()
    ...
    >>> f = ContactFormWithDepartment(auto_id=False)
    >>> print(f)
    <div>Subject:<input type="text" name="subject" maxlength="100" required></div>
    <div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
    <div>Contact email:<input type="email" name="contact_email" required></div>
    <div>Urgent:<input type="checkbox" name="urgent"></div>
    <div>Department:<input type="text" name="department" required></div>

Il est possible d’hériter de plusieurs formulaires, en considérant ces formulaires comme des « mixins ». Dans cet exemple, `BeatleForm` hérite à la fois de `PersonForm` et de `InstrumentForm` (dans cet ordre), et sa liste de champs contient les champs de ses classes parentes :

    >>> from django import forms
    >>> class PersonForm(forms.Form):
    ...     first_name = forms.CharField()
    ...     last_name = forms.CharField()
    ...
    >>> class InstrumentForm(forms.Form):
    ...     instrument = forms.CharField()
    ...
    >>> class BeatleForm(InstrumentForm, PersonForm):
    ...     haircut_type = forms.CharField()
    ...
    >>> b = BeatleForm(auto_id=False)
    >>> print(b)
    <div>First name:<input type="text" name="first_name" required></div>
    <div>Last name:<input type="text" name="last_name" required></div>
    <div>Instrument:<input type="text" name="instrument" required></div>
    <div>Haircut type:<input type="text" name="haircut_type" required></div>

Il est possible d’enlever de manière déclarative un champ `Field` hérité d’une classe parente en définissant son nom à `None` dans la sous-classe. Par exemple :

    >>> from django import forms

    >>> class ParentForm(forms.Form):
    ...     name = forms.CharField()
    ...     age = forms.IntegerField()
    ...

    >>> class ChildForm(ParentForm):
    ...     name = None
    ...

    >>> list(ChildForm().fields)
    ['age']

## Préfixes de formulaires

Form.prefix

Une balise `<form>` peut contenir plusieurs formulaires Django. Afin que chaque formulaire possède son propre espace de noms, utilisez le paramètre nommé `prefix`:

    >>> mother = PersonForm(prefix="mother")
    >>> father = PersonForm(prefix="father")
    >>> print(mother)
    <div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
    <div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
    >>> print(father)
    <div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
    <div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>

Le préfixe peut aussi être défini au niveau de la classe de formulaire :

    >>> class PersonForm(forms.Form):
    ...     ...
    ...     prefix = "person"
    ...