{"title":"基于类的视图","version":"6.1","locale":"zh-hans","docname":"topics/class-based-views/intro","url":"/zh-hans/6.1/topics/class-based-views/intro/","canonical":"https://djangodocs.dev/zh-hans/6.1/topics/class-based-views/intro/","summary":"基于类的视图提供另一种将视图实现为 Python 对象而不是函数的方法。它们不能替代基于函数的视图，但与基于函数的视图相比，它们是有某些不同和优势的。 与特定的 HTTP 方法（ GET , POST , 等等）关联的代码组织能通过单独的方法替代条件分支来解决。 面向对象技术（比如 mixins…","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>面向对象技术（比如 mixins 多重继承）可用于将代码分解为可重用组件。</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=\"/zh-hans/6.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=\"/zh-hans/6.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>创建基于类的通用视图与基于函数的通用视图具有相同的目标，那就是使视图开发更容易。然而，通过使用 mixins 实现解决方案的方式提供了一个工具包，使基于类的通用视图比基于函数的通用视图更灵活，更有扩展性。</p>\n<p>如果你之前有尝试过基于函数的通用视图并发现了它的不足之处，那么你不应该认为基于类的通用视图只是基于类的等效视图，而是作为一种新的方法来解决通用视图要解决的原始问题。</p>\n<p>为了获得最大的灵活性，Django 使用基础类和mixins的工具包来构建通用视图，因此在默认方法实现和属性的形式中有很多钩子，你在最简单的用例中不太可能涉及到这些钩子。比如，不要将你限制为 <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\">get_form</span></code> 方法，它调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">get_form_class</span></code> 方法，在默认实现里只返回类的 <code class=\"docutils literal notranslate\"><span class=\"pre\">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 请求方法，而不是在单个视图函数里使用有条件分支的代码。</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\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=\"s2\">&quot;GET&quot;</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=\"s2\">&quot;result&quot;</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\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=\"s2\">&quot;result&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>因为 Django 的 URL 解析器期望发送请求和相关参数来调动函数而不是类，基于类的视图有一个 <a class=\"reference internal\" href=\"/zh-hans/6.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=\"/zh-hans/6.1/ref/class-based-views/base/#django.views.generic.base.View.setup\" title=\"django.views.generic.base.View.setup\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">setup()</span></code></a> 初始化它的属性，然后调用 <a class=\"reference internal\" href=\"/zh-hans/6.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>，等等。如果它被定义，那么依靠请求来匹配方法，否则会引发 <a class=\"reference internal\" href=\"/zh-hans/6.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=\"s2\">&quot;about/&quot;</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=\"/zh-hans/6.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> 。这意味着 <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/shortcuts/\"><span class=\"doc\">http 快捷函数</span></a> 或 <a class=\"reference internal\" href=\"/zh-hans/6.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> 对象可以使用基于类里的视图。</p>\n<p>虽然基于类的最小视图不需要任何类属性来执行任务，类属性在很多基于类的始终很常见，这里有两种方法来配置或设置类属性。</p>\n<p>第一种是子类化标准 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\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=\"/zh-hans/6.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=\"s2\">&quot;about/&quot;</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\">Note</p>\n<p>当你的类为发送给它的每个请求实例化时，通过 <a class=\"reference internal\" href=\"/zh-hans/6.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> 入口点设置的类属性在导入 URLs  的时候只配置一次。</p>\n</aside>\n</section>\n<section id=\"using-mixins\">\n<h2>使用 mixins<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>Mixins 是一个多继承表单，其中可组合多个父类的行为和属性。</p>\n<p>举例，在通用基于类的视图中，名为 <a class=\"reference internal\" href=\"/zh-hans/6.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> 的 mixin 的首要目的是定义方法 <a class=\"reference internal\" href=\"/zh-hans/6.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>。当与视图的基类行为结合使用时，结果是一个 <a class=\"reference internal\" href=\"/zh-hans/6.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> 类，它将请求分派到适当的匹配方法（在视图基类中定义的行为），并且具有 <a class=\"reference internal\" href=\"/zh-hans/6.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> 方法，该方法使用 <a class=\"reference internal\" href=\"/zh-hans/6.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> 属性返回一个 <a class=\"reference internal\" href=\"/zh-hans/6.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> 对象（在 <code class=\"docutils literal notranslate\"><span class=\"pre\">TemplateResponseMixin</span></code> 中定义的行为）。</p>\n<p>Mixins 是在多个类中重用代码的绝佳方法，但它们需要一些代价。代码分散在 Mixins 中的越多，理解子类并知道它到底在做什么就越困难，而且如果你正在子类化具有深继承树的东西，那么就越难知道要从哪个 mixns 的方法中来覆盖它。</p>\n<p>也需要注意你只能从一个通用视图继承——只有一个父类可以继承自 <a class=\"reference internal\" href=\"/zh-hans/6.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>，剩余的（如果有的话）应该继承自 mixins 。试着从更多的继承自 <code class=\"docutils literal notranslate\"><span class=\"pre\">View</span></code> 的类继承的话——例如试着在列表顶部使用表单并组合 <a class=\"reference internal\" href=\"/zh-hans/6.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> ——将无法按照预期工作。</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\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=\"s2\">&quot;/success/&quot;</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=\"s2\">&quot;key&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;value&quot;</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=\"s2\">&quot;form_template.html&quot;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s2\">&quot;form&quot;</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\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=\"s2\">&quot;key&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;value&quot;</span><span class=\"p\">}</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s2\">&quot;form_template.html&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> <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=\"s2\">&quot;form&quot;</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=\"s2\">&quot;/success/&quot;</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=\"s2\">&quot;form&quot;</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 配置或者子类化和重写一个或多个方法（或者两种都可以）。</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>基于类的视图的扩展不仅限于使用 mixins ，你也可以使用装饰器。因为基于类的视图不是函数，所以根据你是使用 <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=\"/zh-hans/6.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=\"s2\">&quot;about/&quot;</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=\"s2\">&quot;vote/&quot;</span><span class=\"p\">,</span> <span class=\"n\">permission_required</span><span class=\"p\">(</span><span class=\"s2\">&quot;polls.can_vote&quot;</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=\"/zh-hans/6.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\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=\"s2\">&quot;secret.html&quot;</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=\"s2\">&quot;dispatch&quot;</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=\"s2\">&quot;secret.html&quot;</span>\n</code></pre></div>\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=\"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\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=\"s2\">&quot;dispatch&quot;</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=\"s2\">&quot;secret.html&quot;</span>\n\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=\"s2\">&quot;dispatch&quot;</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=\"s2\">&quot;dispatch&quot;</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=\"s2\">&quot;secret.html&quot;</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> 的每一个实例将被登录保护。尽管这些例子使用  <code class=\"docutils literal notranslate\"><span class=\"pre\">login_required</span></code> ，但可以使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/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> 获得同样的行为。</p>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</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":"使用 mixins","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":"/zh-hans/6.1/topics/"},{"docname":"topics/class-based-views/index","title":"基于类的视图","url":"/zh-hans/6.1/topics/class-based-views/"}],"prev":{"docname":"topics/class-based-views/index","title":"基于类的视图","url":"/zh-hans/6.1/topics/class-based-views/"},"next":{"docname":"topics/class-based-views/generic-display","title":"内置的基于类的通用视图","url":"/zh-hans/6.1/topics/class-based-views/generic-display/"},"formats":{"html":"/zh-hans/6.1/topics/class-based-views/intro/","markdown":"/zh-hans/6.1/topics/class-based-views/intro.md","json":"/zh-hans/6.1/topics/class-based-views/intro.json"},"source":"https://github.com/django/django/blob/stable/6.1.x/docs/topics/class-based-views/intro.txt","official":"https://docs.djangoproject.com/zh-hans/6.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"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}