---
title: "Gestion de formulaires avec les vues fondées sur les classes"
version: 2.0
locale: fr
source: https://docs.djangoproject.com/fr/2.0/topics/class-based-views/generic-editing/
canonical: https://djangodocs.dev/fr/2.0/topics/class-based-views/generic-editing/
---
# Gestion de formulaires avec les vues fondées sur les classes

Le traitement de formulaires utilise généralement trois parcours :

- Affichage initial GET (vierge ou contenu pré-rempli)
- Envoi POST avec données non valides (réaffiche normalement le formulaire avec indication des erreurs)
- Envoi POST avec données valides (traitement des données normalement suivi par une redirection)

Lorsqu’on implémente soi-même ces étapes, il en résulte souvent beaucoup de code répétitif (voir [Utilisation d’un formulaire dans une vue](/fr/2.0/topics/forms/#using-a-form-in-a-view)). Pour l’éviter, Django fournit un ensemble de vues génériques fondées sur les classes dédiées au traitement des vues.

## Formulaires élémentaires

Étant donné un formulaire simple de contact :

*forms.py*

```
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField()
    message = forms.CharField(widget=forms.Textarea)

    def send_email(self):
        # send email using the self.cleaned_data dictionary
        pass
```

La vue peut être construite en utilisant une classe `FormView`:

*views.py*

```
from myapp.forms import ContactForm
from django.views.generic.edit import FormView

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'

    def form_valid(self, form):
        # This method is called when valid form data has been POSTed.
        # It should return an HttpResponse.
        form.send_email()
        return super().form_valid(form)
```

Notes :

- `FormView` hérite de [`TemplateResponseMixin`](/fr/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin), ce qui fait qu’on peut utiliser [`template_name`](/fr/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) à cet endroit.
- L’implémentation par défaut de [`form_valid()`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_valid) redirige simplement vers [`success_url`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.success_url).

## Formulaires de modèles

Les vues génériques brillent particulièrement lorsqu’elles interagissent avec des modèles. Ces vues génériques vont automatiquement créer un formulaire [`ModelForm`](/fr/2.0/topics/forms/modelforms/#django.forms.ModelForm), pour autant qu’elles puissent déterminer la classe de modèle à utiliser :

- Si l’attribut [`model`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.model) est présent, c’est cette classe de modèle qui sera utilisée.
- Si [`get_object()`](/fr/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object) renvoie un objet, c’est la classe de cet objet qui sera utilisée.
- Si un attribut [`queryset`](/fr/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.queryset) est présent, c’est le modèle correspondant à ce jeu de requête qui sera utilisé.

Les vues de formulaire de modèle contiennent une implémentation de [`form_valid()`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid) qui enregistre automatiquement le modèle. Vous pouvez surcharger cela si vous avez des exigences particulières ; voir ci-dessous pour des exemples.

Vous n’avez même pas besoin d’indiquer un attribut `success_url` pour [`CreateView`](/fr/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView) ou [`UpdateView`](/fr/2.0/ref/class-based-views/generic-editing/#django.views.generic.edit.UpdateView), elles vont utiliser [`get_absolute_url()`](/fr/2.0/ref/models/instances/#django.db.models.Model.get_absolute_url) sur l’objet de modèle le cas échéant.

Si vous souhaitez utiliser un formulaire [`ModelForm`](/fr/2.0/topics/forms/modelforms/#django.forms.ModelForm) personnalisé (par exemple pour ajouter de la validation en plus), il suffit de définir [`form_class`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class) dans la vue.

> **Note**
>
> Lorsqu’une classe de formulaire personnalisée est présente, il est toujours nécessaire de définir le modèle, même si la classe [`form_class`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class) est une classe [`ModelForm`](/fr/2.0/topics/forms/modelforms/#django.forms.ModelForm).

Nous devons d’abord ajouter une méthode [`get_absolute_url()`](/fr/2.0/ref/models/instances/#django.db.models.Model.get_absolute_url) à notre classe `Author`:

*models.py*

```
from django.db import models
from django.urls import reverse

class Author(models.Model):
    name = models.CharField(max_length=200)

    def get_absolute_url(self):
        return reverse('author-detail', kwargs={'pk': self.pk})
```

Puis nous pouvons utiliser [`CreateView`](/fr/2.0/ref/class-based-views/flattened-index/#CreateView) et compagnie pour faire le travail. Remarquez que nous avons ici juste à configurer les vues génériques fondées sur les classes ; nous n’avons pas à écrire nous-même de logique de vue :

*views.py*

```
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

class AuthorUpdate(UpdateView):
    model = Author
    fields = ['name']

class AuthorDelete(DeleteView):
    model = Author
    success_url = reverse_lazy('author-list')
```

> **Note**
>
> Nous devons utiliser [`reverse_lazy()`](/fr/2.0/ref/urlresolvers/#django.urls.reverse_lazy) ici, pas simplement `reverse()` car la configuration d’URL n’est pas chargée au moment où le fichier est importé.

L’attribut `fields` fonctionne de la même manière que l’attribut `fields` de la classe interne `Meta` de [`ModelForm`](/fr/2.0/topics/forms/modelforms/#django.forms.ModelForm). Sauf dans les cas où la classe de formulaire est définie d’une autre manière, cet attribut est obligatoire et la vue génère une exception [`ImproperlyConfigured`](/fr/2.0/ref/exceptions/#django.core.exceptions.ImproperlyConfigured) s’il est absent.

Si vous définissez à la fois les attributs [`fields`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.fields) et [`form_class`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class), une exception [`ImproperlyConfigured`](/fr/2.0/ref/exceptions/#django.core.exceptions.ImproperlyConfigured) est générée.

Finalement, nous connectons ces nouvelles vues dans la configuration d’URL :

*urls.py*

```
from django.urls import path
from myapp.views import AuthorCreate, AuthorDelete, AuthorUpdate

urlpatterns = [
    # ...
    path('author/add/', AuthorCreate.as_view(), name='author-add'),
    path('author/<int:pk>/', AuthorUpdate.as_view(), name='author-update'),
    path('author/<int:pk>/delete/', AuthorDelete.as_view(), name='author-delete'),
]
```

> **Note**
>
> Ces vues héritent de [`SingleObjectTemplateResponseMixin`](/fr/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin) qui utilise [`template_name_suffix`](/fr/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix) pour construire [`template_name`](/fr/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) en fonction du modèle.
>
> Dans cet exemple :
>
> - [`CreateView`](/fr/2.0/ref/class-based-views/flattened-index/#CreateView) et [`UpdateView`](/fr/2.0/ref/class-based-views/flattened-index/#UpdateView) utilisent `myapp/author_form.html`
> - [`DeleteView`](/fr/2.0/ref/class-based-views/flattened-index/#DeleteView) utilise `myapp/author_confirm_delete.html`
>
> Si vous aimeriez avoir des gabarits séparés pour  [`CreateView`](/fr/2.0/ref/class-based-views/flattened-index/#CreateView) et [`UpdateView`](/fr/2.0/ref/class-based-views/flattened-index/#UpdateView), vous pouvez définir [`template_name`](/fr/2.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name) ou [`template_name_suffix`](/fr/2.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix) dans votre classe de vue.

## Modèles et `request.user`

Pour garder trace de l’utilisateur ayant créé un objet en utilisant [`CreateView`](/fr/2.0/ref/class-based-views/flattened-index/#CreateView), vous pouvez utiliser un formulaire [`ModelForm`](/fr/2.0/topics/forms/modelforms/#django.forms.ModelForm) personnalisé. Premièrement, ajoutez la relation de clé étrangère dans le modèle :

*models.py*

```
from django.contrib.auth.models import User
from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=200)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)

    # ...
```

Dans la vue, prenez soin de ne pas inclure `created_by` dans la liste des champs modifiables et surchargez [`form_valid()`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid) afin d’ajouter l’utilisateur :

*views.py*

```
from django.views.generic.edit import CreateView
from myapp.models import Author

class AuthorCreate(CreateView):
    model = Author
    fields = ['name']

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)
```

Notez que vous devrez [décorer cette vue](/fr/2.0/topics/class-based-views/intro/#id1) par [`login_required()`](/fr/2.0/topics/auth/default/#django.contrib.auth.decorators.login_required) ou trouver un autre moyen de gérer les accès d’utilisateurs non autorisés dans [`form_valid()`](/fr/2.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid).

## Exemple AJAX

Voici un exemple simple montrant une possible implémentation d’un formulaire fonctionnant aussi bien pour des requêtes AJAX que pour des envois de formulaire POST « normaux » :

```
from django.http import JsonResponse
from django.views.generic.edit import CreateView
from myapp.models import Author

class AjaxableResponseMixin:
    """
    Mixin to add AJAX support to a form.
    Must be used with an object-based FormView (e.g. CreateView)
    """
    def form_invalid(self, form):
        response = super().form_invalid(form)
        if self.request.is_ajax():
            return JsonResponse(form.errors, status=400)
        else:
            return response

    def form_valid(self, form):
        # We make sure to call the parent's form_valid() method because
        # it might do some processing (in the case of CreateView, it will
        # call form.save() for example).
        response = super().form_valid(form)
        if self.request.is_ajax():
            data = {
                'pk': self.object.pk,
            }
            return JsonResponse(data)
        else:
            return response

class AuthorCreate(AjaxableResponseMixin, CreateView):
    model = Author
    fields = ['name']
```
