{"title":"クラスベースのビューでフォームを扱う","version":"5.2","locale":"ja","docname":"topics/class-based-views/generic-editing","url":"/ja/5.2/topics/class-based-views/generic-editing/","canonical":"https://djangodocs.dev/ja/5.2/topics/class-based-views/generic-editing/","summary":"フォームの処理には、一般に3つの場合分けが存在します。これらの処理を自分で実装しようとすると、多くの場合、多数の繰り返しの定型コードを書くことになってしまいま…","html":"<h1>クラスベースのビューでフォームを扱う<a class=\"heading-anchor\" href=\"#form-handling-with-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>フォームの処理には、一般に3つの場合分けが存在します。</p>\n<ul class=\"simple\">\n<li><p>最初の GET リクエスト (空白またはデフォルト値が埋め込まれたフォームを返す)</p></li>\n<li><p>無効なデータの POST リクエスト (よくあるパターンは、エラー表示を追加したフォームを再表示する)</p></li>\n<li><p>有効なデータの POST リクエスト (データを処理し、普通はリダイレクトを行う)</p></li>\n</ul>\n<p>これらの処理を自分で実装しようとすると、多くの場合、多数の繰り返しの定型コードを書くことになってしまいます (<a class=\"reference internal\" href=\"/ja/5.2/topics/forms/#using-a-form-in-a-view\"><span class=\"std std-ref\">ビューでフォームを使う</span></a> を参照)。これを避けるために、Django はフォームを処理するための一般的なクラスビューを用意しています。</p>\n<section id=\"basic-forms\">\n<h2>基本的なフォーム<a class=\"heading-anchor\" href=\"#basic-forms\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>以下のようなコンタクトフォームがあったとします。</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">forms.py</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=\"nn\">django</span> <span class=\"kn\">import</span> forms\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ContactForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">()</span>\n    message <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>Textarea<span class=\"p\">)</span>\n\n    <span class=\"k\">def</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>このとき、ビューは <code class=\"docutils literal notranslate\">FormView</code> を使うことで構築できます。</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">views.py</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=\"nn\">myapp.forms</span> <span class=\"kn\">import</span> ContactForm\n<span class=\"kn\">from</span> <span class=\"nn\">django.views.generic.edit</span> <span class=\"kn\">import</span> FormView\n\n\n<span class=\"k\">class</span> <span class=\"nc\">ContactFormView</span><span class=\"p\">(</span>FormView<span class=\"p\">):</span>\n    template_name <span class=\"o\">=</span> <span class=\"s2\">&quot;contact.html&quot;</span>\n    form_class <span class=\"o\">=</span> ContactForm\n    success_url <span class=\"o\">=</span> <span class=\"s2\">&quot;/thanks/&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<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        form<span class=\"o\">.</span>send_email<span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_valid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n</code></pre></figure>\n<p>メモ:</p>\n<ul class=\"simple\">\n<li><p>FormView は <a class=\"reference internal\" href=\"/ja/5.2/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\">TemplateResponseMixin</code></a> を継承するため、ここでは <a class=\"reference internal\" href=\"/ja/5.2/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\">template_name</code></a> を使うことができます。</p></li>\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/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\">form_valid()</code></a> デフォルトの実装は、ただ単に <a class=\"reference internal\" href=\"/ja/5.2/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\">success_url</code></a> にリダイレクトするというものです。</p></li>\n</ul>\n</section>\n<section id=\"model-forms\">\n<h2>モデルフォーム<a class=\"heading-anchor\" href=\"#model-forms\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>ジェネリックビューが輝きを見せるのは、モデルとともに使用した時です。ジェネリックビューは  <a class=\"reference internal\" href=\"/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> を自動的に生成するので、どのモデルクラスを使うのかを選択できます。</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/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\">model</code></a> 属性が与えられた場合には、そのモデルクラスが使用されます。</p></li>\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/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\">get_object()</code></a> がオブジェクトを帰す場合には、そのオブジェクトのクラスが使用されます。</p></li>\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/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\">queryset</code></a> が与えられた場合には、そのクエリセットに対するモデルが使用されます。</p></li>\n</ul>\n<p>モデルフォームビューはモデルを自動的に保存する <a class=\"reference internal\" href=\"/ja/5.2/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\">form_valid()</code></a> 実装を提供します。 もし特別な要件があれば、これをオーバーライドできます。以下の例を参照してください。</p>\n<p><a class=\"reference internal\" href=\"/ja/5.2/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\">CreateView</code></a> や <a class=\"reference internal\" href=\"/ja/5.2/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\">UpdateView</code></a> には <code class=\"docutils literal notranslate\">success_url</code> を指定する必要はありません。モデルオブジェクトに <a class=\"reference internal\" href=\"/ja/5.2/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\">get_absolute_url()</code></a> があればそれを使用します。</p>\n<p>カスタムの <a class=\"reference internal\" href=\"/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> を使いたい場合 (インスタンスでバリデーションを追加したい場合)、 <a class=\"reference internal\" href=\"/ja/5.2/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\">form_class</code></a> をビューに指定してください。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">注釈</p>\n<p>カスタムのフォームクラスを指定した場合、<a class=\"reference internal\" href=\"/ja/5.2/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\">form_class</code></a> が <a class=\"reference internal\" href=\"/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> だったとしても、モデルを指定する必要があります。</p>\n</aside>\n<p>最初に、<code class=\"docutils literal notranslate\">Author</code> クラスに <a class=\"reference internal\" href=\"/ja/5.2/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\">get_absolute_url()</code></a> を追加する必要があります:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">models.py</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=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n<span class=\"kn\">from</span> <span class=\"nn\">django.urls</span> <span class=\"kn\">import</span> reverse\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Author</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</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> reverse<span class=\"p\">(</span><span class=\"s2\">&quot;author-detail&quot;</span><span class=\"p\">,</span> kwargs<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>pk<span class=\"p\">})</span>\n</code></pre></figure>\n<p>そうしたら、<a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\">CreateView</code></a> およびその仲間たちを使って実際に動作させることができます。ここでは一般的なクラスベースのビューのみを設定している点が重要です; 自分自身でロジックを書く必要はありません:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">views.py</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=\"nn\">django.urls</span> <span class=\"kn\">import</span> reverse_lazy\n<span class=\"kn\">from</span> <span class=\"nn\">django.views.generic.edit</span> <span class=\"kn\">import</span> CreateView<span class=\"p\">,</span> DeleteView<span class=\"p\">,</span> UpdateView\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span>CreateView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Author\n    fields <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=\"nc\">AuthorUpdateView</span><span class=\"p\">(</span>UpdateView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Author\n    fields <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=\"nc\">AuthorDeleteView</span><span class=\"p\">(</span>DeleteView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Author\n    success_url <span class=\"o\">=</span> reverse_lazy<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\">注釈</p>\n<p>ファイルがインポートされるときに urls は読み込まれないので、 <a class=\"reference internal\" href=\"/ja/5.2/ref/urlresolvers/#django.urls.reverse_lazy\" title=\"django.urls.reverse_lazy\"><code class=\"xref py py-func docutils literal notranslate\">reverse_lazy()</code></a> を <code class=\"docutils literal notranslate\">reverse()</code> の代わりに使う必要があります。</p>\n</aside>\n<p><code class=\"docutils literal notranslate\">fields</code> 属性は <a class=\"reference internal\" href=\"/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> の内部 <code class=\"docutils literal notranslate\">Meta</code> クラスの <code class=\"docutils literal notranslate\">fields</code> 属性と同じように動作します。別の方法でフォームクラスを定義しない限り、この属性は必須であり、属性がない場合、ビューは <a class=\"reference internal\" href=\"/ja/5.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured\" title=\"django.core.exceptions.ImproperlyConfigured\"><code class=\"xref py py-exc docutils literal notranslate\">ImproperlyConfigured</code></a> 例外を発生させます。</p>\n<p><a class=\"reference internal\" href=\"/ja/5.2/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\">fields</code></a> 属性と <a class=\"reference internal\" href=\"/ja/5.2/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\">form_class</code></a> 属性の両方を指定した場合、 <a class=\"reference internal\" href=\"/ja/5.2/ref/exceptions/#django.core.exceptions.ImproperlyConfigured\" title=\"django.core.exceptions.ImproperlyConfigured\"><code class=\"xref py py-exc docutils literal notranslate\">ImproperlyConfigured</code></a> 例外が発生します。</p>\n<p>最後に、これらの新しいビューをURLconfにフックします:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">urls.py</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=\"nn\">django.urls</span> <span class=\"kn\">import</span> path\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.views</span> <span class=\"kn\">import</span> AuthorCreateView<span class=\"p\">,</span> AuthorDeleteView<span class=\"p\">,</span> AuthorUpdateView\n\nurlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"c1\"># ...</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;author/add/&quot;</span><span class=\"p\">,</span> AuthorCreateView<span class=\"o\">.</span>as_view<span class=\"p\">(),</span> name<span class=\"o\">=</span><span class=\"s2\">&quot;author-add&quot;</span><span class=\"p\">),</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;author/&lt;int:pk&gt;/&quot;</span><span class=\"p\">,</span> AuthorUpdateView<span class=\"o\">.</span>as_view<span class=\"p\">(),</span> name<span class=\"o\">=</span><span class=\"s2\">&quot;author-update&quot;</span><span class=\"p\">),</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;author/&lt;int:pk&gt;/delete/&quot;</span><span class=\"p\">,</span> AuthorDeleteView<span class=\"o\">.</span>as_view<span class=\"p\">(),</span> name<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\">注釈</p>\n<p>これらのビューは <a class=\"reference internal\" href=\"/ja/5.2/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\">SingleObjectTemplateResponseMixin</code></a> を継承しており、 <a class=\"reference internal\" href=\"/ja/5.2/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\">template_name_suffix</code></a> を使ってモデルに基づいて <a class=\"reference internal\" href=\"/ja/5.2/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\">template_name</code></a> を構成します。</p>\n<p>この例では:</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\">CreateView</code></a> と <a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#UpdateView\" title=\"UpdateView\"><code class=\"xref py py-class docutils literal notranslate\">UpdateView</code></a> は <code class=\"docutils literal notranslate\">myapp/author_form.html</code> を使用します。</p></li>\n<li><p><a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#DeleteView\" title=\"DeleteView\"><code class=\"xref py py-class docutils literal notranslate\">DeleteView</code></a> は <code class=\"docutils literal notranslate\">myapp/author_confirm_delete.html</code> を使用します。</p></li>\n</ul>\n<p><a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\">CreateView</code></a> と <a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#UpdateView\" title=\"UpdateView\"><code class=\"xref py py-class docutils literal notranslate\">UpdateView</code></a> で別々のテンプレートを使いたい場合は、 <a class=\"reference internal\" href=\"/ja/5.2/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\">template_name</code></a> か <a class=\"reference internal\" href=\"/ja/5.2/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\">template_name_suffix</code></a> をビュークラスに指定します。</p>\n</aside>\n</section>\n<section id=\"models-and-request-user\">\n<h2>モデルと <code class=\"docutils literal notranslate\">request.user</code><a class=\"heading-anchor\" href=\"#models-and-request-user\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><a class=\"reference internal\" href=\"/ja/5.2/ref/class-based-views/flattened-index/#CreateView\" title=\"CreateView\"><code class=\"xref py py-class docutils literal notranslate\">CreateView</code></a> を使ってオブジェクトを作成したユーザを追跡するには、カスタムの <a class=\"reference internal\" href=\"/ja/5.2/topics/forms/modelforms/#django.forms.ModelForm\" title=\"django.forms.ModelForm\"><code class=\"xref py py-class docutils literal notranslate\">ModelForm</code></a> を使います。まず、モデルに外部キー関係を追加します：</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">models.py</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=\"nn\">django.contrib.auth.models</span> <span class=\"kn\">import</span> User\n<span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Author</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">200</span><span class=\"p\">)</span>\n    created_by <span class=\"o\">=</span> models<span class=\"o\">.</span>ForeignKey<span class=\"p\">(</span>User<span class=\"p\">,</span> on_delete<span class=\"o\">=</span>models<span class=\"o\">.</span>CASCADE<span class=\"p\">)</span>\n\n    <span class=\"c1\"># ...</span>\n</code></pre></figure>\n<p>ビューでは、編集するフィールドのリストに <code class=\"docutils literal notranslate\">created_by</code> が含まれていないことを確認し、 <a class=\"reference internal\" href=\"/ja/5.2/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\">form_valid()</code></a> をオーバーライドしてユーザーを追加します:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\">views.py</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=\"nn\">django.contrib.auth.mixins</span> <span class=\"kn\">import</span> LoginRequiredMixin\n<span class=\"kn\">from</span> <span class=\"nn\">django.views.generic.edit</span> <span class=\"kn\">import</span> CreateView\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span>LoginRequiredMixin<span class=\"p\">,</span> CreateView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Author\n    fields <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=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<span class=\"p\">):</span>\n        form<span class=\"o\">.</span>instance<span class=\"o\">.</span>created_by <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>request<span class=\"o\">.</span>user\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_valid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/ja/5.2/topics/auth/default/#django.contrib.auth.mixins.LoginRequiredMixin\" title=\"django.contrib.auth.mixins.LoginRequiredMixin\"><code class=\"xref py py-class docutils literal notranslate\">LoginRequiredMixin</code></a> はログインしていないユーザーがフォームにアクセスできないようにします。これを省略した場合、 <a class=\"reference internal\" href=\"/ja/5.2/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\">form_valid()</code></a> で未承認ユーザを処理する必要があります。</p>\n</section>\n<section id=\"content-negotiation-example\">\n<span id=\"id1\"></span><h2>コンテンツネゴシエーションの例<a class=\"heading-anchor\" href=\"#content-negotiation-example\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>ここでは、API ベースのワークフローと「通常の」フォーム POST で動作するフォームの実装例を紹介します:</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=\"nn\">django.http</span> <span class=\"kn\">import</span> JsonResponse\n<span class=\"kn\">from</span> <span class=\"nn\">django.views.generic.edit</span> <span class=\"kn\">import</span> CreateView\n<span class=\"kn\">from</span> <span class=\"nn\">myapp.models</span> <span class=\"kn\">import</span> Author\n\n\n<span class=\"k\">class</span> <span class=\"nc\">JsonableResponseMixin</span><span class=\"p\">:</span>\n    <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=\"nf\">form_invalid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<span class=\"p\">):</span>\n        response <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_invalid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span>request<span class=\"o\">.</span>accepts<span class=\"p\">(</span><span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> response\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> JsonResponse<span class=\"p\">(</span>form<span class=\"o\">.</span>errors<span class=\"p\">,</span> status<span class=\"o\">=</span><span class=\"mi\">400</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<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        response <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_valid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span>request<span class=\"o\">.</span>accepts<span class=\"p\">(</span><span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">):</span>\n            <span class=\"k\">return</span> response\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            data <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>object<span class=\"o\">.</span>pk<span class=\"p\">,</span>\n            <span class=\"p\">}</span>\n            <span class=\"k\">return</span> JsonResponse<span class=\"p\">(</span>data<span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">AuthorCreateView</span><span class=\"p\">(</span>JsonableResponseMixin<span class=\"p\">,</span> CreateView<span class=\"p\">):</span>\n    model <span class=\"o\">=</span> Author\n    fields <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;name&quot;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>上の例では、クライアントが <code class=\"docutils literal notranslate\">text/html</code> をサポートしている場合、それを優先するという前提になっています。しかし、これは常に正しいとは限りません。たとえば、<code class=\"docutils literal notranslate\">.css</code> ファイルをリクエストする際、多くのブラウザは <code class=\"docutils literal notranslate\">Accept: text/css,*/*;q=0.1</code> というヘッダーを送信し、CSS を優先するが他の形式でも構わないという意図を示します。この場合でも <code class=\"docutils literal notranslate\">request.accepts(&quot;text/html&quot;)</code> は <code class=\"docutils literal notranslate\">True</code> を返します。</p>\n<p>クライアントの優先度を考慮して正しいフォーマットを判断するには、 <a class=\"reference internal\" href=\"/ja/5.2/ref/request-response/#django.http.HttpRequest.get_preferred_type\" title=\"django.http.HttpRequest.get_preferred_type\"><code class=\"xref py py-func docutils literal notranslate\">django.http.HttpRequest.get_preferred_type()</code></a> を使用してください。</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=\"k\">class</span> <span class=\"nc\">JsonableResponseMixin</span><span class=\"p\">:</span>\n    <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    accepted_media_types <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;application/json&quot;</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">dispatch</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> request<span class=\"p\">,</span> <span class=\"o\">*</span>args<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">):</span>\n        <span class=\"k\">if</span> request<span class=\"o\">.</span>get_preferred_type<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>accepted_media_types<span class=\"p\">)</span> <span class=\"ow\">is</span> <span class=\"kc\">None</span><span class=\"p\">:</span>\n            <span class=\"c1\"># No format in common.</span>\n            <span class=\"k\">return</span> HttpResponse<span class=\"p\">(</span>\n                status_code<span class=\"o\">=</span><span class=\"mi\">406</span><span class=\"p\">,</span> headers<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;Accept&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;,&quot;</span><span class=\"o\">.</span>join<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>accepted_media_types<span class=\"p\">)}</span>\n            <span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>dispatch<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"o\">*</span>args<span class=\"p\">,</span> <span class=\"o\">**</span>kwargs<span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">form_invalid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<span class=\"p\">):</span>\n        response <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_invalid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n        accepted_type <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>request<span class=\"o\">.</span>get_preferred_type<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>accepted_media_types<span class=\"p\">)</span>\n        <span class=\"k\">if</span> accepted_type <span class=\"o\">==</span> <span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> response\n        <span class=\"k\">elif</span> accepted_type <span class=\"o\">==</span> <span class=\"s2\">&quot;application/json&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> JsonResponse<span class=\"p\">(</span>form<span class=\"o\">.</span>errors<span class=\"p\">,</span> status<span class=\"o\">=</span><span class=\"mi\">400</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">form_valid</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> form<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        response <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>form_valid<span class=\"p\">(</span>form<span class=\"p\">)</span>\n        accepted_type <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span>request<span class=\"o\">.</span>get_preferred_type<span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span>accepted_media_types<span class=\"p\">)</span>\n        <span class=\"k\">if</span> accepted_type <span class=\"o\">==</span> <span class=\"s2\">&quot;text/html&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> response\n        <span class=\"k\">elif</span> accepted_type <span class=\"o\">==</span> <span class=\"s2\">&quot;application/json&quot;</span><span class=\"p\">:</span>\n            data <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>object<span class=\"o\">.</span>pk<span class=\"p\">,</span>\n            <span class=\"p\">}</span>\n            <span class=\"k\">return</span> JsonResponse<span class=\"p\">(</span>data<span class=\"p\">)</span>\n</code></pre></div>\n<aside class=\"version-note version-changed\" data-version=\"5.2\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 5.2</p><p><a class=\"reference internal\" href=\"/ja/5.2/ref/request-response/#django.http.HttpRequest.get_preferred_type\" title=\"django.http.HttpRequest.get_preferred_type\"><code class=\"xref py py-meth docutils literal notranslate\">HttpRequest.get_preferred_type()</code></a> メソッドが追加されました。</p>\n</aside>\n</section>","rootId":"form-handling-with-class-based-views","toc":[{"title":"基本的なフォーム","anchor":"basic-forms","children":[]},{"title":"モデルフォーム","anchor":"model-forms","children":[]},{"title":"モデルと request.user","anchor":"models-and-request-user","children":[]},{"title":"コンテンツネゴシエーションの例","anchor":"content-negotiation-example","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"Django を使う","url":"/ja/5.2/topics/"},{"docname":"topics/class-based-views/index","title":"クラスベースビュー","url":"/ja/5.2/topics/class-based-views/"}],"prev":{"docname":"topics/class-based-views/generic-display","title":"組み込みのクラスベースのジェネリックビュー（汎用ビュー）","url":"/ja/5.2/topics/class-based-views/generic-display/"},"next":{"docname":"topics/class-based-views/mixins","title":"クラスベースのビューでミックスイン (mixin) を使用する","url":"/ja/5.2/topics/class-based-views/mixins/"},"formats":{"html":"/ja/5.2/topics/class-based-views/generic-editing/","markdown":"/ja/5.2/topics/class-based-views/generic-editing.md","json":"/ja/5.2/topics/class-based-views/generic-editing.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/topics/class-based-views/generic-editing.txt","official":"https://docs.djangoproject.com/ja/5.2/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","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}