{"title":"条件视图处理","version":"4.2","locale":"zh-hans","docname":"topics/conditional-view-processing","url":"/zh-hans/4.2/topics/conditional-view-processing/","canonical":"https://djangodocs.dev/zh-hans/4.2/topics/conditional-view-processing/","summary":"HTTP 客户端可以发送一些头部信息，用来告诉服务器它们已经看过的资源的副本情况。这通常在检索网页（使用 HTTP 的 GET 请求）时使用，以避免发送客户端已经检索过的内容数据。然而，这些相同的头部信息可以用于所有 HTTP 方法（ POST ， PUT ， DELETE 等）。 针对每个从 Django…","html":"<h1>条件视图处理<a class=\"heading-anchor\" href=\"#conditional-view-processing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>HTTP 客户端可以发送一些头部信息，用来告诉服务器它们已经看过的资源的副本情况。这通常在检索网页（使用 HTTP 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 请求）时使用，以避免发送客户端已经检索过的内容数据。然而，这些相同的头部信息可以用于所有 HTTP 方法（<code class=\"docutils literal notranslate\"><span class=\"pre\">POST</span></code>，<code class=\"docutils literal notranslate\"><span class=\"pre\">PUT</span></code>，<code class=\"docutils literal notranslate\"><span class=\"pre\">DELETE</span></code> 等）。</p>\n<p>针对每个从 Django 视图返回的页面（响应），它可能提供了两种HTTP headers：<code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> header 和  <code class=\"docutils literal notranslate\"><span class=\"pre\">Last-Modified</span></code> header。这些 headers 是 HTTP 的可选项。他们可以在视图函数里设置，或者依赖 <a class=\"reference internal\" href=\"/zh-hans/4.2/ref/middleware/#django.middleware.http.ConditionalGetMiddleware\" title=\"django.middleware.http.ConditionalGetMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ConditionalGetMiddleware</span></code></a> 中间件来设置 <code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> header 。</p>\n<p>当客户端下次请求相同资源时，它可能会发送一个类似 <span class=\"target\" id=\"index-16\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-13.1.3\"><strong>If-Modified-Since</strong></a> 或 <span class=\"target\" id=\"index-17\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-13.1.4\"><strong>If-Unmodified-Since</strong></a> 的头部，其中包含了上次发送的最后修改时间的日期，或者 <span class=\"target\" id=\"index-18\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-13.1.1\"><strong>If-Match</strong></a> 或 <span class=\"target\" id=\"index-19\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-13.1.2\"><strong>If-None-Match</strong></a>，其中包含了最后的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code>。如果页面的当前版本与客户端发送的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> 匹配，或者资源没有被修改，可以发送一个 304 状态码，而不是一个完整的响应，告诉客户端没有变化。根据头部的不同，如果页面已经被修改或者与客户端发送的 <code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> 不匹配，可能会返回一个 412 状态码（前提条件失败）。</p>\n<p>当你需要更多的控制，你可以使用针对每个视图的条件处理函数。</p>\n<section id=\"the-condition-decorator\">\n<span id=\"conditional-decorators\"></span><h2>条件装饰器<a class=\"heading-anchor\" href=\"#the-condition-decorator\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有时（事实上，相当经常），你可以创建函数来快速计算资源的 <span class=\"target\" id=\"index-20\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-8.8.3\"><strong>ETag</strong></a> 值或最后修改时间，<strong>而不需要</strong> 执行构建完整视图所需的所有计算。Django 可以使用这些函数来提供视图处理的“提前退出”选项。告诉客户端内容自上次请求以来没有被修改，也许是这样。</p>\n<p>这两个函数被当做参数传递到 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.views.decorators.http.condition</span></code> 装饰器。这个装饰器使用两个函数（你只需要支持其中一个，如果你不能很快计算这两个数量）来判断 HTTP 请求的 headers 和这些资源是否匹配。如果它们没有匹配，会计算一份资源的副本，并调用视图。</p>\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=\"n\">condition</span><span class=\"p\">(</span><span class=\"n\">etag_func</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">last_modified_func</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>用于计算 ETag 和最后修改时间的两个函数将接收传入的 <code class=\"docutils literal notranslate\"><span class=\"pre\">request</span></code> 对象和与它们帮助包装的视图函数中的相同参数，以相同的顺序。传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">last_modified_func</span></code> 的函数应返回一个标准的日期时间值，指定资源上次修改的时间，如果资源不存在则返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>。传递给 <code class=\"docutils literal notranslate\"><span class=\"pre\">etag</span></code> 装饰器的函数应返回表示资源的 <span class=\"target\" id=\"index-21\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-8.8.3\"><strong>ETag</strong></a> 的字符串，如果资源不存在则返回 <code class=\"docutils literal notranslate\"><span class=\"pre\">None</span></code>。</p>\n<p>如果它们没有通过视图设置并且请求的方法是安全的(<code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">HEAD</span></code>)，那么装饰器就会在请求上设置 <code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Last-Modified</span></code> headers 。</p>\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\">import</span><span class=\"w\"> </span><span class=\"nn\">datetime</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">models</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Blog</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Entry</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"n\">blog</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">ForeignKey</span><span class=\"p\">(</span><span class=\"n\">Blog</span><span class=\"p\">,</span> <span class=\"n\">on_delete</span><span class=\"o\">=</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">CASCADE</span><span class=\"p\">)</span>\n    <span class=\"n\">published</span> <span class=\"o\">=</span> <span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">DateTimeField</span><span class=\"p\">(</span><span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">)</span>\n    <span class=\"o\">...</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\">def</span><span class=\"w\"> </span><span class=\"nf\">latest_entry</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">blog_id</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">blog</span><span class=\"o\">=</span><span class=\"n\">blog_id</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">latest</span><span class=\"p\">(</span><span class=\"s2\">&quot;published&quot;</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">published</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.views.decorators.http</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">condition</span>\n\n\n<span class=\"nd\">@condition</span><span class=\"p\">(</span><span class=\"n\">last_modified_func</span><span class=\"o\">=</span><span class=\"n\">latest_entry</span><span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">front_page</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">blog_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</code></pre></div>\n<aside class=\"admonition-be-careful-with-the-order-of-decorators admonition\">\n<p class=\"admonition-title\">小心装饰器的顺序</p>\n<p>当 <code class=\"docutils literal notranslate\"><span class=\"pre\">condition()</span></code> 返回一个条件响应时，任何位于它下面的装饰器都会被跳过，不会应用于响应。因此，任何需要应用于常规视图响应和条件响应的装饰器必须位于 <code class=\"docutils literal notranslate\"><span class=\"pre\">condition()</span></code> 之上。特别是，<a class=\"reference internal\" href=\"/zh-hans/4.2/topics/http/decorators/#django.views.decorators.vary.vary_on_cookie\" title=\"django.views.decorators.vary.vary_on_cookie\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">vary_on_cookie()</span></code></a>、<a class=\"reference internal\" href=\"/zh-hans/4.2/topics/http/decorators/#django.views.decorators.vary.vary_on_headers\" title=\"django.views.decorators.vary.vary_on_headers\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">vary_on_headers()</span></code></a>  和 <a class=\"reference internal\" href=\"/zh-hans/4.2/topics/http/decorators/#django.views.decorators.cache.cache_control\" title=\"django.views.decorators.cache.cache_control\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">cache_control()</span></code></a> 应该放在前面，因为 <span class=\"target\" id=\"index-22\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-15.4.5\"><strong>RFC 9110</strong></a> 要求它们设置的标头在 304 响应中存在。</p>\n</aside>\n</section>\n<section id=\"shortcuts-for-only-computing-one-value\">\n<h2>仅用于计算一个值的快捷方式<a class=\"heading-anchor\" href=\"#shortcuts-for-only-computing-one-value\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>作为常用规则，如果你可以提供函数去同时计算 ETag 和最后的修改时间，你应该这样做。你不知道任何给定的 HTTP 客户端将向你发送哪一个headers，因此需要同时处理这两个headers。然而，有时候只有一个值易于计算，Django 提供的装饰器处理只有 ETag 或 只有 last-modified 的计算。</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">django.views.decorators.http.etag</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.views.decorators.http.last_modified</span></code> 装饰器和 <code class=\"docutils literal notranslate\"><span class=\"pre\">condition</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\">etag</span><span class=\"p\">(</span><span class=\"n\">etag_func</span><span class=\"p\">)</span>\n<span class=\"n\">last_modified</span><span class=\"p\">(</span><span class=\"n\">last_modified_func</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>我们可以使用其中一个装饰器来编写更早一些的那个只使用last-modified函数的例子：</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\">@last_modified</span><span class=\"p\">(</span><span class=\"n\">latest_entry</span><span class=\"p\">)</span>\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">front_page</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">blog_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</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\">def</span><span class=\"w\"> </span><span class=\"nf\">front_page</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"p\">,</span> <span class=\"n\">blog_id</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n\n\n<span class=\"n\">front_page</span> <span class=\"o\">=</span> <span class=\"n\">last_modified</span><span class=\"p\">(</span><span class=\"n\">latest_entry</span><span class=\"p\">)(</span><span class=\"n\">front_page</span><span class=\"p\">)</span>\n</code></pre></div>\n<section id=\"use-condition-when-testing-both-conditions\">\n<h3>测试两个条件时使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">condition</span></code><a class=\"heading-anchor\" href=\"#use-condition-when-testing-both-conditions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你想测试两个先决条件，那么试着链接 <code class=\"docutils literal notranslate\"><span class=\"pre\">etag</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">last_modified</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=\"c1\"># Bad code. Don&#39;t do this!</span>\n<span class=\"nd\">@etag</span><span class=\"p\">(</span><span class=\"n\">etag_func</span><span class=\"p\">)</span>\n<span class=\"nd\">@last_modified</span><span class=\"p\">(</span><span class=\"n\">last_modified_func</span><span class=\"p\">)</span>\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=\"o\">...</span>\n\n\n<span class=\"c1\"># End of bad code.</span>\n</code></pre></div>\n<p>第一个装饰器不知道关于第二个装饰器的任何信息，而且可能回答“这个响应没有被修改”，即使第二个装饰器确定不是那样。<code class=\"docutils literal notranslate\"><span class=\"pre\">condition</span></code> 装饰器同时使用两个回调函数来执行正确的动作。</p>\n</section>\n</section>\n<section id=\"using-the-decorators-with-other-http-methods\">\n<h2>将装饰器和其他 HTTP 方法一起使用<a class=\"heading-anchor\" href=\"#using-the-decorators-with-other-http-methods\"><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\">condition</span></code> 装饰器不仅仅用于 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">HEAD</span></code> 请求（在这个解决方案里 <code class=\"docutils literal notranslate\"><span class=\"pre\">HEAD``请求和</span> <span class=\"pre\">``GET</span></code> 类似）。它也可以被用于提供  <code class=\"docutils literal notranslate\"><span class=\"pre\">POST</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">PUT</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">DELETE</span></code> 请求的检查。在这些情况下，不会返回一个“未修改”的响应，但会告诉客户端它们尝试修改的资源在这期间已被修改。</p>\n<p>例如，在客户端和服务端之间考虑下面的交换：</p>\n<ol class=\"arabic simple\">\n<li><p>用户请求``/foo/<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>。</p></li>\n<li><p>服务端用一些带有 <code class=\"docutils literal notranslate\"><span class=\"pre\">&quot;abcd1234&quot;</span></code> 的 ETag 响应一些内容。</p></li>\n<li><p>客户端发送一个 HTTP <code class=\"docutils literal notranslate\"><span class=\"pre\">PUT</span></code> 请求到 <code class=\"docutils literal notranslate\"><span class=\"pre\">/foo/</span></code> 来更新一些资源。它也发送 <code class=\"docutils literal notranslate\"><span class=\"pre\">If-Match:</span> <span class=\"pre\">&quot;abcd1234&quot;</span></code> header 来指定它准备更新的版本。</p></li>\n<li><p>服务端通过计算 ETag（与 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 请求计算的方式相同，使用相同的函数）来检查资源是否被修改。如果资源被改变，它将返回 412 状态码，意思是 &quot;先决条件失败&quot; 。</p></li>\n<li><p>客户端在收到一个412响应后会发送一个 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 请求到 <code class=\"docutils literal notranslate\"><span class=\"pre\">/foo/</span></code>，在更新它之前用来寻找内容更新的版本。</p></li>\n</ol>\n<p>重要的是这个例子显示的是相同函数在所有情形下可以被用来计算ETag和最后一次修改。事实上，你应该使用相同的函数，这样相同的值会被实时返回。</p>\n<aside class=\"admonition-validator-headers-with-non-safe-request-methods admonition\">\n<p class=\"admonition-title\">具有不安全请求方法的验证 headers</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">condition</span></code> 装饰器仅为安全的 HTTP 方法（即 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">HEAD</span></code>）设置验证器标头（<code class=\"docutils literal notranslate\"><span class=\"pre\">ETag</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Last-Modified</span></code>）。如果您希望在其他情况下返回它们，请在视图中设置它们。请参阅 <span class=\"target\" id=\"index-23\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.3.4\"><strong>RFC 9110 Section 9.3.4</strong></a> 了解在响应使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">PUT</span></code> 与 <code class=\"docutils literal notranslate\"><span class=\"pre\">POST</span></code> 进行的请求时设置验证器标头的区别。</p>\n</aside>\n</section>\n<section id=\"comparison-with-middleware-conditional-processing\">\n<h2>对比中间件的条件处理<a class=\"heading-anchor\" href=\"#comparison-with-middleware-conditional-processing\"><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/4.2/ref/middleware/#django.middleware.http.ConditionalGetMiddleware\" title=\"django.middleware.http.ConditionalGetMiddleware\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.middleware.http.ConditionalGetMiddleware</span></code></a> 提供了有条件的 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 处理。虽然易于使用，但是中间件在高级用法上是有限制的：</p>\n<ul class=\"simple\">\n<li><p>它可被全局应用于项目的所有视图。</p></li>\n<li><p>它不会阻止你生成响应，这样代价可能很昂贵。</p></li>\n<li><p>它只适合HTTP 的 <code class=\"docutils literal notranslate\"><span class=\"pre\">GET</span></code> 请求。</p></li>\n</ul>\n<p>你应该为你的特殊需求选择最合适的工具。如果你有方法可以很迅速地计算 ETags 和 修改时间，并且如果一些视图花了一些时间去生成内容，那么你应该在这个文档中考虑使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">condition</span></code> 装饰器描述。如果所有事务都运行的非常快了，那么坚持使用中间件。如果视图没有变动，那么发送回客户端的网络流量将仍然会减少。</p>\n</section>","rootId":"conditional-view-processing","toc":[{"title":"条件装饰器","anchor":"the-condition-decorator","children":[]},{"title":"仅用于计算一个值的快捷方式","anchor":"shortcuts-for-only-computing-one-value","children":[{"title":"测试两个条件时使用 condition","anchor":"use-condition-when-testing-both-conditions","children":[]}]},{"title":"将装饰器和其他 HTTP 方法一起使用","anchor":"using-the-decorators-with-other-http-methods","children":[]},{"title":"对比中间件的条件处理","anchor":"comparison-with-middleware-conditional-processing","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.2/topics/"}],"prev":{"docname":"topics/cache","title":"Django 缓存框架","url":"/zh-hans/4.2/topics/cache/"},"next":{"docname":"topics/signing","title":"加密签名","url":"/zh-hans/4.2/topics/signing/"},"formats":{"html":"/zh-hans/4.2/topics/conditional-view-processing/","markdown":"/zh-hans/4.2/topics/conditional-view-processing.md","json":"/zh-hans/4.2/topics/conditional-view-processing.json"},"source":"https://github.com/django/django/blob/stable/4.2.x/docs/topics/conditional-view-processing.txt","official":"https://docs.djangoproject.com/zh-hans/4.2/topics/conditional-view-processing/","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","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}