{"title":"Gestion de formulaires avec les vues fondées sur les classes","version":"5.0","locale":"fr","docname":"topics/class-based-views/generic-editing","url":"/fr/5.0/topics/class-based-views/generic-editing/","canonical":"https://djangodocs.dev/fr/5.0/topics/class-based-views/generic-editing/","summary":"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…","html":"<h1>Gestion de formulaires avec les vues fondées sur les classes<a class=\"heading-anchor\" href=\"#form-handling-with-class-based-views\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Le traitement de formulaires utilise généralement trois parcours :</p>\n<ul class=\"simple\">\n<li><p>Affichage initial GET (vierge ou contenu pré-rempli)</p></li>\n<li><p>Envoi POST avec données non valides (réaffiche normalement le formulaire avec indication des erreurs)</p></li>\n<li><p>Envoi POST avec données valides (traitement des données normalement suivi par une redirection)</p></li>\n</ul>\n<p>Lorsqu’on implémente soi-même ces étapes, il en résulte souvent beaucoup de code répétitif (voir <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/#using-a-form-in-a-view\"><span class=\"std std-ref\">Utilisation d’un formulaire dans une vue</span></a>). Pour l’éviter, Django fournit un ensemble de vues génériques fondées sur les classes dédiées au traitement des vues.</p>\n<section id=\"basic-forms\">\n<h2>Formulaires élémentaires<a class=\"heading-anchor\" href=\"#basic-forms\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Étant donné un formulaire de contact :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">forms.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">forms</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ContactForm</span><span class=\"p\">(</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Form</span><span class=\"p\">):</span>\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">()</span>\n    <span class=\"n\">message</span> <span class=\"o\">=</span> <span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">widget</span><span class=\"o\">=</span><span class=\"n\">forms</span><span class=\"o\">.</span><span class=\"n\">Textarea</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">send_email</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># send email using the self.cleaned_data dictionary</span>\n        <span class=\"k\">pass</span>\n</code></pre></figure>\n<p>La vue peut être construite en utilisant une classe <code class=\"docutils literal notranslate\"><span class=\"pre\">FormView</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">ContactForm</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic.edit</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">FormView</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ContactFormView</span><span class=\"p\">(</span><span class=\"n\">FormView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;contact.html&quot;</span>\n    <span class=\"n\">form_class</span> <span class=\"o\">=</span> <span class=\"n\">ContactForm</span>\n    <span class=\"n\">success_url</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;/thanks/&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">form</span><span class=\"p\">):</span>\n        <span class=\"c1\"># This method is called when valid form data has been POSTed.</span>\n        <span class=\"c1\"># It should return an HttpResponse.</span>\n        <span class=\"n\">form</span><span class=\"o\">.</span><span class=\"n\">send_email</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">form_valid</span><span class=\"p\">(</span><span class=\"n\">form</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Notes :</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">FormView</span></code> hérite de <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin\" title=\"django.views.generic.base.TemplateResponseMixin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponseMixin</span></code></a>, ce qui fait qu’on peut utiliser <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name\" title=\"django.views.generic.base.TemplateResponseMixin.template_name\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">template_name</span></code></a> à cet endroit.</p></li>\n<li><p>L’implémentation par défaut de <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_valid\" title=\"django.views.generic.edit.FormMixin.form_valid\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">form_valid()</span></code></a> redirige simplement vers <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.success_url\" title=\"django.views.generic.edit.FormMixin.success_url\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">success_url</span></code></a>.</p></li>\n</ul>\n</section>\n<section id=\"model-forms\">\n<h2>Formulaires de modèles<a class=\"heading-anchor\" href=\"#model-forms\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>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 <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code></a>, pour autant qu’elles puissent déterminer la classe de modèle à utiliser :</p>\n<ul class=\"simple\">\n<li><p>Si l’attribut <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.model\" title=\"django.views.generic.edit.ModelFormMixin.model\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">model</span></code></a> est présent, c’est cette classe de modèle qui sera utilisée.</p></li>\n<li><p>Si <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.get_object\" title=\"django.views.generic.detail.SingleObjectMixin.get_object\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">get_object()</span></code></a> renvoie un objet, c’est la classe de cet objet qui sera utilisée.</p></li>\n<li><p>Si un attribut <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.queryset\" title=\"django.views.generic.detail.SingleObjectMixin.queryset\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">queryset</span></code></a> est présent, c’est le modèle correspondant à ce jeu de requête qui sera utilisé.</p></li>\n</ul>\n<p>Les vues de formulaire de modèle contiennent une implémentation de <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid\" title=\"django.views.generic.edit.ModelFormMixin.form_valid\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">form_valid()</span></code></a> qui enregistre automatiquement le modèle. Vous pouvez surcharger cela si vous avez des exigences particulières ; voir ci-dessous pour des exemples.</p>\n<p>Vous n’avez même pas besoin d’indiquer un attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">success_url</span></code> pour <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/generic-editing/#django.views.generic.edit.CreateView\" title=\"django.views.generic.edit.CreateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CreateView</span></code></a> ou <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/generic-editing/#django.views.generic.edit.UpdateView\" title=\"django.views.generic.edit.UpdateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UpdateView</span></code></a>, elles vont utiliser <a class=\"reference internal\" href=\"/fr/5.0/ref/models/instances/#django.db.models.Model.get_absolute_url\" title=\"django.db.models.Model.get_absolute_url\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">get_absolute_url()</span></code></a> sur l’objet de modèle le cas échéant.</p>\n<p>Si vous souhaitez utiliser un formulaire <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code></a> personnalisé (par exemple pour ajouter de la validation en plus), définissez <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class\" title=\"django.views.generic.edit.FormMixin.form_class\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">form_class</span></code></a> dans la vue.</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>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 <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class\" title=\"django.views.generic.edit.FormMixin.form_class\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">form_class</span></code></a> est une classe <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code></a>.</p>\n</aside>\n<p>Nous devons d’abord ajouter une méthode <a class=\"reference internal\" href=\"/fr/5.0/ref/models/instances/#django.db.models.Model.get_absolute_url\" title=\"django.db.models.Model.get_absolute_url\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">get_absolute_url()</span></code></a> à notre classe <code class=\"docutils literal notranslate\"><span class=\"pre\">Author</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Author</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_absolute_url</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s2\">&quot;author-detail&quot;</span><span class=\"p\">,</span> <span class=\"n\">kwargs</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pk</span><span class=\"p\">})</span>\n</code></pre></figure>\n<p>Puis nous pouvons utiliser <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CreateView</span></code></a> 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 :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse_lazy</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic.edit</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CreateView</span><span class=\"p\">,</span> <span class=\"n\">DeleteView</span><span class=\"p\">,</span> <span class=\"n\">UpdateView</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Author</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span><span class=\"n\">CreateView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Author</span>\n    <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AuthorUpdateView</span><span class=\"p\">(</span><span class=\"n\">UpdateView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Author</span>\n    <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AuthorDeleteView</span><span class=\"p\">(</span><span class=\"n\">DeleteView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Author</span>\n    <span class=\"n\">success_url</span> <span class=\"o\">=</span> <span class=\"n\">reverse_lazy</span><span class=\"p\">(</span><span class=\"s2\">&quot;author-list&quot;</span><span class=\"p\">)</span>\n</code></pre></figure>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Nous devons utiliser <a class=\"reference internal\" href=\"/fr/5.0/ref/urlresolvers/#django.urls.reverse_lazy\" title=\"django.urls.reverse_lazy\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">reverse_lazy()</span></code></a> au lieu de <code class=\"docutils literal notranslate\"><span class=\"pre\">reverse()</span></code> car la configuration d’URL n’est pas encore chargée au moment où le fichier est importé.</p>\n</aside>\n<p>L’attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">fields</span></code> fonctionne de la même manière que l’attribut <code class=\"docutils literal notranslate\"><span class=\"pre\">fields</span></code> de la classe interne <code class=\"docutils literal notranslate\"><span class=\"pre\">Meta</span></code> de <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code></a>. 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 <a class=\"reference internal\" href=\"/fr/5.0/ref/exceptions/#django.core.exceptions.ImproperlyConfigured\" title=\"django.core.exceptions.ImproperlyConfigured\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ImproperlyConfigured</span></code></a> s’il est absent.</p>\n<p>Si vous définissez à la fois les attributs <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.fields\" title=\"django.views.generic.edit.ModelFormMixin.fields\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">fields</span></code></a> et <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.form_class\" title=\"django.views.generic.edit.FormMixin.form_class\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">form_class</span></code></a>, une exception <a class=\"reference internal\" href=\"/fr/5.0/ref/exceptions/#django.core.exceptions.ImproperlyConfigured\" title=\"django.core.exceptions.ImproperlyConfigured\"><code class=\"xref py py-exc docutils literal notranslate\"><span class=\"pre\">ImproperlyConfigured</span></code></a> est générée.</p>\n<p>Finalement, nous connectons ces nouvelles vues dans la configuration d’URL :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">urls.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">path</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">AuthorCreateView</span><span class=\"p\">,</span> <span class=\"n\">AuthorDeleteView</span><span class=\"p\">,</span> <span class=\"n\">AuthorUpdateView</span>\n\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s2\">&quot;author/add/&quot;</span><span class=\"p\">,</span> <span class=\"n\">AuthorCreateView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;author-add&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s2\">&quot;author/&lt;int:pk&gt;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">AuthorUpdateView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;author-update&quot;</span><span class=\"p\">),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s2\">&quot;author/&lt;int:pk&gt;/delete/&quot;</span><span class=\"p\">,</span> <span class=\"n\">AuthorDeleteView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(),</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s2\">&quot;author-delete&quot;</span><span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>Ces vues héritent de <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin\" title=\"django.views.generic.detail.SingleObjectTemplateResponseMixin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">SingleObjectTemplateResponseMixin</span></code></a> qui utilise <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix\" title=\"django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">template_name_suffix</span></code></a> pour construire <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name\" title=\"django.views.generic.base.TemplateResponseMixin.template_name\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">template_name</span></code></a> en fonction du modèle.</p>\n<p>Dans cet exemple :</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CreateView</span></code></a> et <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#UpdateView\" title=\"UpdateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UpdateView</span></code></a> utilisent <code class=\"docutils literal notranslate\"><span class=\"pre\">myapp/author_form.html</span></code></p></li>\n<li><p><a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#DeleteView\" title=\"DeleteView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DeleteView</span></code></a> utilise <code class=\"docutils literal notranslate\"><span class=\"pre\">myapp/author_confirm_delete.html</span></code></p></li>\n</ul>\n<p>Si vous aimeriez avoir des gabarits séparés pour  <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CreateView</span></code></a> et <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#UpdateView\" title=\"UpdateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">UpdateView</span></code></a>, vous pouvez définir <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.template_name\" title=\"django.views.generic.base.TemplateResponseMixin.template_name\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">template_name</span></code></a> ou <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix\" title=\"django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">template_name_suffix</span></code></a> dans votre classe de vue.</p>\n</aside>\n</section>\n<section id=\"models-and-request-user\">\n<h2>Modèles et <code class=\"docutils literal notranslate\"><span class=\"pre\">request.user</span></code><a class=\"heading-anchor\" href=\"#models-and-request-user\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Pour garder trace de l’utilisateur ayant créé un objet en utilisant <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">CreateView</span></code></a>, vous pouvez utiliser un formulaire <a class=\"reference internal\" href=\"/fr/5.0/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ModelForm</span></code></a> personnalisé. Premièrement, ajoutez la relation de clé étrangère dans le modèle :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">User</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Author</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">name</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CharField</span><span class=\"p\">(</span><span class=\"n\">max_length</span><span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n    <span class=\"n\">created_by</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">User</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n\n    <span class=\"c1\"># ...</span>\n</code></pre></figure>\n<p>Dans la vue, prenez soin de ne pas inclure <code class=\"docutils literal notranslate\"><span class=\"pre\">created_by</span></code> dans la liste des champs modifiables et surchargez <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid\" title=\"django.views.generic.edit.ModelFormMixin.form_valid\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">form_valid()</span></code></a> afin d’ajouter l’utilisateur :</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib.auth.mixins</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">LoginRequiredMixin</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic.edit</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CreateView</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Author</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span><span class=\"n\">LoginRequiredMixin</span><span class=\"p\">,</span> <span class=\"n\">CreateView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Author</span>\n    <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">form</span><span class=\"p\">):</span>\n        <span class=\"n\">form</span><span class=\"o\">.</span><span class=\"n\">instance</span><span class=\"o\">.</span><span class=\"n\">created_by</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">user</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">form_valid</span><span class=\"p\">(</span><span class=\"n\">form</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/fr/5.0/topics/auth/default/#django.contrib.auth.mixins.LoginRequiredMixin\" title=\"django.contrib.auth.mixins.LoginRequiredMixin\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">LoginRequiredMixin</span></code></a> empêche les utilisateurs qui ne sont pas authentifiés d’accéder au formulaire. Si vous omettez ça, il sera de votre responsabilité de gérer les utilisateurs non autorisés dans <a class=\"reference internal\" href=\"/fr/5.0/ref/class-based-views/mixins-editing/#django.views.generic.edit.ModelFormMixin.form_valid\" title=\"django.views.generic.edit.ModelFormMixin.form_valid\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">form_valid()</span></code></a>.</p>\n</section>\n<section id=\"content-negotiation-example\">\n<span id=\"id1\"></span><h2>Exemple de négociation de contenu<a class=\"heading-anchor\" href=\"#content-negotiation-example\"><span class=\"visually-hidden\">Lien vers cette rubrique</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Voici un exemple montrant une possible implémentation d’un formulaire fonctionnant aussi bien pour un flux basé sur une API que pour des envois de formulaire POST « normaux » :</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">JsonResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic.edit</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">CreateView</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">myapp.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Author</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">JsonableResponseMixin</span><span class=\"p\">:</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Mixin to add JSON support to a form.</span>\n<span class=\"sd\">    Must be used with an object-based FormView (e.g. CreateView)</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">form_invalid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">form</span><span class=\"p\">):</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">form_invalid</span><span class=\"p\">(</span><span class=\"n\">form</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">accepts</span><span class=\"p\">(</span><span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">response</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"n\">JsonResponse</span><span class=\"p\">(</span><span class=\"n\">form</span><span class=\"o\">.</span><span class=\"n\">errors</span><span class=\"p\">,</span> <span class=\"n\">status</span><span class=\"o\">=</span><span class=\"mi\">400</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">form</span><span class=\"p\">):</span>\n        <span class=\"c1\"># We make sure to call the parent&#39;s form_valid() method because</span>\n        <span class=\"c1\"># it might do some processing (in the case of CreateView, it will</span>\n        <span class=\"c1\"># call form.save() for example).</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">form_valid</span><span class=\"p\">(</span><span class=\"n\">form</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">accepts</span><span class=\"p\">(</span><span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> <span class=\"n\">response</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">data</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n                <span class=\"s2\">&quot;pk&quot;</span><span class=\"p\">:</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">object</span><span class=\"o\">.</span><span class=\"n\">pk</span><span class=\"p\">,</span>\n            <span class=\"p\">}</span>\n            <span class=\"k\">return</span> <span class=\"n\">JsonResponse</span><span class=\"p\">(</span><span class=\"n\">data</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span><span class=\"n\">JsonableResponseMixin</span><span class=\"p\">,</span> <span class=\"n\">CreateView</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Author</span>\n    <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n</section>","rootId":"form-handling-with-class-based-views","toc":[{"title":"Formulaires élémentaires","anchor":"basic-forms","children":[]},{"title":"Formulaires de modèles","anchor":"model-forms","children":[]},{"title":"Modèles et request.user","anchor":"models-and-request-user","children":[]},{"title":"Exemple de négociation de contenu","anchor":"content-negotiation-example","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"Utilisation de Django","url":"/fr/5.0/topics/"},{"docname":"topics/class-based-views/index","title":"Vues fondées sur les classes","url":"/fr/5.0/topics/class-based-views/"}],"prev":{"docname":"topics/class-based-views/generic-display","title":"Vues génériques fondées sur les classes, fournies par Django","url":"/fr/5.0/topics/class-based-views/generic-display/"},"next":{"docname":"topics/class-based-views/mixins","title":"Utilisation de mixins avec les vues fondées sur les classes","url":"/fr/5.0/topics/class-based-views/mixins/"},"formats":{"html":"/fr/5.0/topics/class-based-views/generic-editing/","markdown":"/fr/5.0/topics/class-based-views/generic-editing.md","json":"/fr/5.0/topics/class-based-views/generic-editing.json"},"source":"https://github.com/django/django/blob/stable/5.0.x/docs/topics/class-based-views/generic-editing.txt","official":"https://docs.djangoproject.com/fr/5.0/topics/class-based-views/generic-editing/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}