{"title":"クラスベースビュー入門","version":"2.1","locale":"ja","docname":"topics/class-based-views/intro","url":"/ja/2.1/topics/class-based-views/intro/","canonical":"https://djangodocs.dev/ja/2.1/topics/class-based-views/intro/","summary":"クラスベースビューはビューを実装するもう一つの手段で、関数の代わりに Python のオブジェクトとしてビューを定義します。クラスベースビューは関数ベースのビューを完全に置き換えるものではありませんが、関数ベースのビューと比較して、以下のような違いと利点があります。 特定の HTTP メソッド ( GET 、 POST など)…","html":"<h1>クラスベースビュー入門<a class=\"heading-anchor\" href=\"#introduction-to-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>クラスベースビューはビューを実装するもう一つの手段で、関数の代わりに Python のオブジェクトとしてビューを定義します。クラスベースビューは関数ベースのビューを完全に置き換えるものではありませんが、関数ベースのビューと比較して、以下のような違いと利点があります。</p>\n<ul class=\"simple\">\n<li><p>特定の HTTP メソッド (<code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code>、<code class=\"docutils literal notranslate\"><span class=\"pre\">POST</span></code> など) に関連するコードの集まりを、条件分岐を使ってかき分けるのではなく、それぞれに独立したメソッドを割り当てることができる。</p></li>\n<li><p>ミックスイン (多重継承) などのオブジェクト指向のテクニックを使って、コードを再利用可能なコンポーネントに分解できる。</p></li>\n</ul>\n<section id=\"the-relationship-and-history-of-generic-views-class-based-views-and-class-based-generic-views\">\n<h2>ジェネリックビュー、クラスベースビュー、クラスベースジェネリックビューの関係と歴史的経緯<a class=\"heading-anchor\" href=\"#the-relationship-and-history-of-generic-views-class-based-views-and-class-based-generic-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>まず初めに存在したのは、ビュー関数の規約だけでした。Django は、定義された関数に <a class=\"reference internal\" href=\"/ja/2.1/ref/request-response/#django.http.HttpRequest\" title=\"django.http.HttpRequest\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpRequest</span></code></a> を渡して、<a class=\"reference internal\" href=\"/ja/2.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> が返ってくることを期待していました。Django が提供する機能はこの範囲まででした。</p>\n<p>早い内に、ビューの開発には共通のイディオムやパターンが存在することが認識されるようになりました。こうしたパターンを抽象化し、共通ケースに当てはまるようなビューの開発を楽にするために導入されたのが、関数ベースのジェネリックビューでした。</p>\n<p>関数ベースのジェネリックビューには問題点があり、シンプルなケースは概ねカバーしていたものの、シンプルな設定オプションを超えた拡張やカスタマイズの方法がなく、現実世界で使われる様々なアプリケーションでの利便性を制限してしまっていました。</p>\n<p>クラスベースのジェネリックビューは関数ベースのジェネリックビューと同様に、ビューの開発を楽にすることを目的に作成されました。しかし、ミックスインを使用するなどの実装方法の工夫により、ツールキットを提供することができ、結果として、関数ベースのジェネリックビューに比べて、より拡張性が高く、柔軟なものにすることができました。</p>\n<p>もしあなたが昔、関数ベースのジェネリックビューを使用しようとして、不十分なものだと考えたことがあったのなら、クラスベースのジェネリックビューを単なるクラスベースビューと同等のものとは考えないでください。むしろ、ジェネリックビューが解決しようとしていた元々あった問題を解くための新しいアプローチとして考えてください。</p>\n<p>Django がクラスベースのジェネリックビューを作成する時に使う、ベースクラスやミックスインのツールキットは、最高の柔軟性を持つように設計されており、最も単純なユースケースではおそらく気に掛けることもないような多数のフックを、デフォルトのメソッド実装や属性という形で持っています。たとえば、クラスベースの属性 <code class=\"docutils literal notranslate\"><span class=\"pre\">form_class</span></code> だけを使用するよう制限する代わりに、実際の実装では <code class=\"docutils literal notranslate\"><span class=\"pre\">get_form</span></code> メソッドを呼び出し、ここからさらに、デフォルトでは単にクラスの <code class=\"docutils literal notranslate\"><span class=\"pre\">form_class</span></code> 属性を返すだけの <code class=\"docutils literal notranslate\"><span class=\"pre\">get_form_class</span></code> メソッドを呼び出すようになっています。こうすることで、使用するフォームを特定する際に、単に属性を指定するだけの方法から、完全に動的な呼び出し可能なフックの設定まで、いくつもの選択肢が選べるようになります。簡単なシチュエーションでは、これらのオプションは設計に無意味な複雑さを加えているように感じられるかもしれませんが、こうした仕組みがなければ、より高度な設計を行う際に制限が掛けられてしまうのです。</p>\n</section>\n<section id=\"using-class-based-views\">\n<h2>クラスベースのビューを使用する<a class=\"heading-anchor\" href=\"#using-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>中核となる機能として、クラスベースのビューでは、HTTP リクエストのメソッドに応じてクラスインスタンスの異なるメソッドを呼び出させることができるため、1つのビュー関数の内部で条件分岐を使わずにすみます。</p>\n<p>そのため、ビュー関数の場合に HTTP <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> をハンドリングするコードが次のようになるとすると、</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\">HttpResponse</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">my_view</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s1\">&#39;GET&#39;</span><span class=\"p\">:</span>\n        <span class=\"c1\"># &lt;view logic&gt;</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>クラスベースのビューでは以下のようになります。</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\">HttpResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">View</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyView</span><span class=\"p\">(</span><span class=\"n\">View</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"c1\"># &lt;view logic&gt;</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"s1\">&#39;result&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Django の URL リゾルバーはリクエストと関連する引数を、クラスではなく呼び出し可能な関数に渡すことを想定しているため、クラスベースのビューには <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.as_view\" title=\"django.views.generic.base.View.as_view\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">as_view()</span></code></a> クラスメソッドが用意されています。このメソッドは、関連するパターンにマッチする URL へのリクエストが届いた時に呼ばれる関数を返します。そして、この関数はクラスのインスタンスを作成して、<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.dispatch\" title=\"django.views.generic.base.View.dispatch\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">dispatch()</span></code></a> メソッドを呼びます。<code class=\"docutils literal notranslate\"><span class=\"pre\">dispatch</span></code> はリクエストを見て <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> や <code class=\"docutils literal notranslate\"><span class=\"pre\">POST</span></code> などの HTTP メソッドを判定し、マッチするメソッドが定義されていればリクエストを受け渡します。もし定義されていない場合には、<a class=\"reference internal\" href=\"/ja/2.1/ref/request-response/#django.http.HttpResponseNotAllowed\" title=\"django.http.HttpResponseNotAllowed\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponseNotAllowed</span></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=\"c1\"># urls.py</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\">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\">MyView</span>\n\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;about/&#39;</span><span class=\"p\">,</span> <span class=\"n\">MyView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">()),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>メソッドが関数ベースのビューが返すもの、つまり何らかの形の <a class=\"reference internal\" href=\"/ja/2.1/ref/request-response/#django.http.HttpResponse\" title=\"django.http.HttpResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">HttpResponse</span></code></a> と同等のものしか返せないなら意味はありません。これが意味するのは、<span class=\"xref std std-doc\">http shortcuts ` や :class:`~django.template.response.TemplateResponse</span> オブジェクトはクラスベースのビューの内部でも使えるということです。</p>\n<p>最小限のクラスベースのビューでは、ジョブを実行するのにどんなクラス属性も必要としませんが、クラスベースの設計をする場合にはクラス属性が役に立つことが多いです。クラス属性のカスタマイズと設定を行うには2つの方法があります。</p>\n<p>第1の方法は、通常の Python のサブクラス化を行い、サブクラス上で属性やメソッドを上書きするという方法です。たとえば、次のように親クラスが <code class=\"docutils literal notranslate\"><span class=\"pre\">greeting</span></code> という属性を持っていたとすると、</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\">HttpResponse</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">View</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">GreetingView</span><span class=\"p\">(</span><span class=\"n\">View</span><span class=\"p\">):</span>\n    <span class=\"n\">greeting</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;Good Day&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">):</span>\n        <span class=\"k\">return</span> <span class=\"n\">HttpResponse</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">greeting</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>サブクラスでは次のように属性を上書きできます。</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=\"w\"> </span><span class=\"nc\">MorningGreetingView</span><span class=\"p\">(</span><span class=\"n\">GreetingView</span><span class=\"p\">):</span>\n    <span class=\"n\">greeting</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;Morning to ya&quot;</span>\n</code></pre></div>\n<p>もう一つの方法は、URLconf 内での <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.as_view\" title=\"django.views.generic.base.View.as_view\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">as_view()</span></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=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;about/&#39;</span><span class=\"p\">,</span> <span class=\"n\">GreetingView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(</span><span class=\"n\">greeting</span><span class=\"o\">=</span><span class=\"s2\">&quot;G&#39;day&quot;</span><span class=\"p\">)),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">注釈</p>\n<p>定義したクラスはリクエストが発行されるごとにインスタンス化されますが、<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.as_view\" title=\"django.views.generic.base.View.as_view\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">as_view()</span></code></a> エントリーポイントで指定したクラス属性が設定されるのは、URL がインポートされる際の1回だけです。</p>\n</aside>\n</section>\n<section id=\"using-mixins\">\n<h2>ミックスインを使用する<a class=\"heading-anchor\" href=\"#using-mixins\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>ミックスインは、複数の親クラスのメソッドや属性を混合することができる多重継承の形式の1つです。</p>\n<p>For example, in the generic class-based views there is a mixin called\n<a class=\"reference internal\" href=\"/ja/2.1/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> whose primary purpose\nis to define the method\n<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response\" title=\"django.views.generic.base.TemplateResponseMixin.render_to_response\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">render_to_response()</span></code></a>.\nWhen combined with the behavior of the <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View\" title=\"django.views.generic.base.View\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">View</span></code></a>\nbase class, the result is a <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.TemplateView\" title=\"django.views.generic.base.TemplateView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateView</span></code></a>\nclass that will dispatch requests to the appropriate matching methods (a\nbehavior defined in the <code class=\"docutils literal notranslate\"><span class=\"pre\">View</span></code> base class), and that has a\n<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/mixins-simple/#django.views.generic.base.TemplateResponseMixin.render_to_response\" title=\"django.views.generic.base.TemplateResponseMixin.render_to_response\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">render_to_response()</span></code></a>\nmethod that uses a\n<a class=\"reference internal\" href=\"/ja/2.1/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>\nattribute to return a <a class=\"reference internal\" href=\"/ja/2.1/ref/template-response/#django.template.response.TemplateResponse\" title=\"django.template.response.TemplateResponse\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">TemplateResponse</span></code></a>\nobject (a behavior defined in the <code class=\"docutils literal notranslate\"><span class=\"pre\">TemplateResponseMixin</span></code>).</p>\n<p>Mixins are an excellent way of reusing code across multiple classes, but they\ncome with some cost. The more your code is scattered among mixins, the harder\nit will be to read a child class and know what exactly it is doing, and the\nharder it will be to know which methods from which mixins to override if you\nare subclassing something that has a deep inheritance tree.</p>\n<p>Note also that you can only inherit from one generic view - that is, only one\nparent class may inherit from <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View\" title=\"django.views.generic.base.View\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">View</span></code></a> and\nthe rest (if any) should be mixins. Trying to inherit from more than one class\nthat inherits from <code class=\"docutils literal notranslate\"><span class=\"pre\">View</span></code> - for example, trying to use a form at the top of a\nlist and combining <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.ProcessFormView\" title=\"django.views.generic.edit.ProcessFormView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ProcessFormView</span></code></a> and\n<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a> - won't work as expected.</p>\n</section>\n<section id=\"handling-forms-with-class-based-views\">\n<h2>クラスベースのビューでフォームを扱う<a class=\"heading-anchor\" href=\"#handling-forms-with-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>フォームを扱う基本の関数ベースのビューは、次のようなコードになります。</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\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">render</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">MyForm</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">myview</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        <span class=\"n\">form</span> <span class=\"o\">=</span> <span class=\"n\">MyForm</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">POST</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">form</span><span class=\"o\">.</span><span class=\"n\">is_valid</span><span class=\"p\">():</span>\n            <span class=\"c1\"># &lt;process form cleaned data&gt;</span>\n            <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"s1\">&#39;/success/&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">form</span> <span class=\"o\">=</span> <span class=\"n\">MyForm</span><span class=\"p\">(</span><span class=\"n\">initial</span><span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">})</span>\n\n    <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"s1\">&#39;form_template.html&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> <span class=\"n\">form</span><span class=\"p\">})</span>\n</code></pre></div>\n<p>同等のクラスベースのビューは、次のようになるでしょう。</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\">HttpResponseRedirect</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.shortcuts</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">render</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">View</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.forms</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">MyForm</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">MyFormView</span><span class=\"p\">(</span><span class=\"n\">View</span><span class=\"p\">):</span>\n    <span class=\"n\">form_class</span> <span class=\"o\">=</span> <span class=\"n\">MyForm</span>\n    <span class=\"n\">initial</span> <span class=\"o\">=</span> <span class=\"p\">{</span><span class=\"s1\">&#39;key&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;value&#39;</span><span class=\"p\">}</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;form_template.html&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"n\">form</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">form_class</span><span class=\"p\">(</span><span class=\"n\">initial</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">initial</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">template_name</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> <span class=\"n\">form</span><span class=\"p\">})</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">post</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"n\">form</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">form_class</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">POST</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">form</span><span class=\"o\">.</span><span class=\"n\">is_valid</span><span class=\"p\">():</span>\n            <span class=\"c1\"># &lt;process form cleaned data&gt;</span>\n            <span class=\"k\">return</span> <span class=\"n\">HttpResponseRedirect</span><span class=\"p\">(</span><span class=\"s1\">&#39;/success/&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">return</span> <span class=\"n\">render</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">template_name</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;form&#39;</span><span class=\"p\">:</span> <span class=\"n\">form</span><span class=\"p\">})</span>\n</code></pre></div>\n<p>これは非常にシンプルなケースですが、クラス属性を上書きするなどの方法でこのビューをカスタマイズする手段が用意されていることがわかります。たとえば、<code class=\"docutils literal notranslate\"><span class=\"pre\">form_class</span></code> を URLconf 設定で指定したり、サブクラス化して1つ以上のメソッドを上書きしたりすることもできます。</p>\n</section>\n<section id=\"decorating-class-based-views\">\n<h2>クラスベースのビューをデコレーションする<a class=\"heading-anchor\" href=\"#decorating-class-based-views\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>クラスベースのビューを拡張する方法は、ミックスインの使用にとどまりません。デコレータも使用できます。クラスベースのビューは関数ではないので、<code class=\"docutils literal notranslate\"><span class=\"pre\">as_view()</span></code> を使用した場合とサブクラスを作成した場合では、デコレータは違った動作をします。</p>\n<section id=\"decorating-in-urlconf\">\n<h3>URLconf でデコレーションする<a class=\"heading-anchor\" href=\"#decorating-in-urlconf\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>クラスベースのビューをデコレーションする最も単純な方法は、<a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.as_view\" title=\"django.views.generic.base.View.as_view\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">as_view()</span></code></a> メソッドの結果をデコレートするというものです。これが最も簡単にできる場所は、ビューをデプロイする URLconf の中です。</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.contrib.auth.decorators</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">login_required</span><span class=\"p\">,</span> <span class=\"n\">permission_required</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">TemplateView</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.views</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">VoteView</span>\n\n<span class=\"n\">urlpatterns</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;about/&#39;</span><span class=\"p\">,</span> <span class=\"n\">login_required</span><span class=\"p\">(</span><span class=\"n\">TemplateView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">(</span><span class=\"n\">template_name</span><span class=\"o\">=</span><span class=\"s2\">&quot;secret.html&quot;</span><span class=\"p\">))),</span>\n    <span class=\"n\">path</span><span class=\"p\">(</span><span class=\"s1\">&#39;vote/&#39;</span><span class=\"p\">,</span> <span class=\"n\">permission_required</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls.can_vote&#39;</span><span class=\"p\">)(</span><span class=\"n\">VoteView</span><span class=\"o\">.</span><span class=\"n\">as_view</span><span class=\"p\">())),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>このアプローチではデコレータはインスタンスごとに適用されます。もしあるビューのすべてのインスタンスをデコレーションしたいばあいは、別のアプローチを取る必要があります。</p>\n</section>\n<section id=\"decorating-the-class\">\n<span id=\"id1\"></span><h3>クラスをデコレーションする<a class=\"heading-anchor\" href=\"#decorating-the-class\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>クラスベースのビューのすべてのインスタンスをデコレーションするには、クラスの定義自体をデコレーションする必要があります。そのためには、クラスの <a class=\"reference internal\" href=\"/ja/2.1/ref/class-based-views/base/#django.views.generic.base.View.dispatch\" title=\"django.views.generic.base.View.dispatch\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">dispatch()</span></code></a> メソッドにデコレータを付けます。</p>\n<p>クラス上のメソッドはスタンドアロンの関数と完全に同じではないため、関数デコレータを単純にそのままメソッドに適用することはできません。適用前にメソッドデコレータに変換する必要があります。<code class=\"docutils literal notranslate\"><span class=\"pre\">method_decorator</span></code> デコレータを使えば、関数デコレータをメソッドデコレータに変換し、インスタンスのメソッドのデコレーションに使えるようにできます。たとえば、次のように使用します。</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.contrib.auth.decorators</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">login_required</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils.decorators</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">method_decorator</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.views.generic</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">TemplateView</span>\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ProtectedView</span><span class=\"p\">(</span><span class=\"n\">TemplateView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;secret.html&#39;</span>\n\n    <span class=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">login_required</span><span class=\"p\">)</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">dispatch</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</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\">dispatch</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>あるいは、より簡潔に、クラスを代わりにデコレートして、デコレーション対象のメソッド名をキーワード引数 <code class=\"docutils literal notranslate\"><span class=\"pre\">name</span></code> に渡すという方法もあります。</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=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">login_required</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;dispatch&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ProtectedView</span><span class=\"p\">(</span><span class=\"n\">TemplateView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;secret.html&#39;</span>\n</code></pre></div>\n<p>共通のデコレータ群が複数の場所で呼ばれる場合には、デコレータのリストまたはタプルを定義して、これを <code class=\"docutils literal notranslate\"><span class=\"pre\">method_decorator()</span></code> を複数回呼ぶ代わりに使用できます。以下の2つのクラスは同じになります。</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=\"n\">decorators</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">never_cache</span><span class=\"p\">,</span> <span class=\"n\">login_required</span><span class=\"p\">]</span>\n\n<span class=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">decorators</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;dispatch&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ProtectedView</span><span class=\"p\">(</span><span class=\"n\">TemplateView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;secret.html&#39;</span>\n\n<span class=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">never_cache</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;dispatch&#39;</span><span class=\"p\">)</span>\n<span class=\"nd\">@method_decorator</span><span class=\"p\">(</span><span class=\"n\">login_required</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&#39;dispatch&#39;</span><span class=\"p\">)</span>\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ProtectedView</span><span class=\"p\">(</span><span class=\"n\">TemplateView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;secret.html&#39;</span>\n</code></pre></div>\n<p>デコレータは、デコレータに渡された順番でリクエストを処理します。上の例では、<code class=\"docutils literal notranslate\"><span class=\"pre\">never_cache()</span></code> が <code class=\"docutils literal notranslate\"><span class=\"pre\">login_required()</span></code> の前にリクエストを処理します。</p>\n<p>この例では、<code class=\"docutils literal notranslate\"><span class=\"pre\">ProtectedView</span></code> のすべてのインスタンスがログインをプロテクトされます。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">注釈</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">method_decorator</span></code> は、クラスのデコレートするメソッドに <code class=\"docutils literal notranslate\"><span class=\"pre\">*args</span></code> と <code class=\"docutils literal notranslate\"><span class=\"pre\">**kwargs</span></code> を引数として渡します。定義されているメソッドが互換性のある引数のセットを受け取れない場合には <code class=\"docutils literal notranslate\"><span class=\"pre\">TypeError</span></code> 例外が発生します。</p>\n</aside>\n</section>\n</section>","rootId":"introduction-to-class-based-views","toc":[{"title":"ジェネリックビュー、クラスベースビュー、クラスベースジェネリックビューの関係と歴史的経緯","anchor":"the-relationship-and-history-of-generic-views-class-based-views-and-class-based-generic-views","children":[]},{"title":"クラスベースのビューを使用する","anchor":"using-class-based-views","children":[]},{"title":"ミックスインを使用する","anchor":"using-mixins","children":[]},{"title":"クラスベースのビューでフォームを扱う","anchor":"handling-forms-with-class-based-views","children":[]},{"title":"クラスベースのビューをデコレーションする","anchor":"decorating-class-based-views","children":[{"title":"URLconf でデコレーションする","anchor":"decorating-in-urlconf","children":[]},{"title":"クラスをデコレーションする","anchor":"decorating-the-class","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"Django を使う","url":"/ja/2.1/topics/"},{"docname":"topics/class-based-views/index","title":"クラスベースビュー","url":"/ja/2.1/topics/class-based-views/"}],"prev":{"docname":"topics/class-based-views/index","title":"クラスベースビュー","url":"/ja/2.1/topics/class-based-views/"},"next":{"docname":"topics/class-based-views/generic-display","title":"ビルトインのクラスベースのジェネリックビュー","url":"/ja/2.1/topics/class-based-views/generic-display/"},"formats":{"html":"/ja/2.1/topics/class-based-views/intro/","markdown":"/ja/2.1/topics/class-based-views/intro.md","json":"/ja/2.1/topics/class-based-views/intro.json"},"source":"https://github.com/django/django/blob/stable/2.1.x/docs/topics/class-based-views/intro.txt","official":"https://docs.djangoproject.com/ja/2.1/topics/class-based-views/intro/","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","pt-br","ko","es","el","pl"]}