{"title":"Django 缓存框架","version":"6.1","locale":"zh-hans","docname":"topics/cache","url":"/zh-hans/6.1/topics/cache/","canonical":"https://djangodocs.dev/zh-hans/6.1/topics/cache/","summary":"动态网站的一个基本权衡是它们是动态的。每当用户请求页面时，Web 服务器进行各种计算，从数据库查询到模板渲染到业务逻辑，以创建您网站访问者看到的页面。","html":"<h1>Django 缓存框架<a class=\"heading-anchor\" href=\"#django-s-cache-framework\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>动态网站的一个基本权衡是它们是动态的。每当用户请求页面时，Web 服务器进行各种计算，从数据库查询到模板渲染到业务逻辑，以创建您网站访问者看到的页面。从处理开销的角度来看，这比标准的从文件系统中读取文件的服务器安排要昂贵得多。</p>\n<p>For most web applications, this overhead isn't a big deal. Most web\napplications aren't <code class=\"docutils literal notranslate\">washingtonpost.com</code> or <code class=\"docutils literal notranslate\">slashdot.org</code>; they're\nsmall-to medium-sized sites with so-so traffic. But for medium- to high-traffic\nsites, it's essential to cut as much overhead as possible.</p>\n<p>这就是缓存的用武之地。</p>\n<p>缓存是指保存昂贵计算的结果，以便下次无需再次执行计算。以下是一些伪代码，说明了如何为动态生成的网页实现缓存：</p>\n<div class=\"code-block\" data-language=\"text\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Text</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=\"Text code\"><code>given a URL, try finding that page in the cache\nif the page is in the cache:\n    return the cached page\nelse:\n    generate the page\n    save the generated page in the cache (for next time)\n    return the generated page\n</code></pre></div>\n<p>Django 自带强大的缓存系统，可以让你保存动态页面，这样就不必为每次请求计算。为了方便，Django 提供了不同级别的缓存粒度。你可以缓存特定视图的输出，你可以只缓存难以生成的部分，或者你可以缓存整个网站。</p>\n<p>Django 也与 &quot;下游&quot; 缓存很好地配合，比如 <a class=\"reference external\" href=\"http://www.squid-cache.org/\">Squid</a> 和基于浏览器的缓存。这些是您不直接控制但可以通过 HTTP 标头提供提示的缓存类型，用于指示哪些部分的网站应该被缓存，以及如何缓存。</p>\n<aside class=\"admonition admonition-seealso\" role=\"note\">\n<p class=\"admonition-title\">See also</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/6.1/misc/design-philosophies/#cache-design-philosophy\"><span class=\"std std-ref\">缓存框架设计理念</span></a> 解释了框架的一些设计决策。</p>\n</aside>\n<section id=\"setting-up-the-cache\">\n<span id=\"id1\"></span><h2>设置缓存<a class=\"heading-anchor\" href=\"#setting-up-the-cache\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>缓存系统需要少量的设置。也就是说，你必须告诉它你的缓存数据应该放在哪里 —— 是在数据库中，还是在文件系统上，或者直接放在内存中。这是一个重要的决定，会影响你的缓存的性能；是的，有些缓存类型比其他类型快。</p>\n<p>你的缓存首选项在设置文件中的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 设置中。以下是所有可用值对 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 的解释。</p>\n<section id=\"memcached\">\n<span id=\"id2\"></span><h3>Memcached<a class=\"heading-anchor\" href=\"#memcached\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://memcached.org/\">Memcached</a> 是一个完全基于内存的缓存服务器，最初是为了处理 LiveJournal.com 上的高负载而开发的，并随后由 Danga Interactive 开源。它被类似 Facebook 和 Wikipedia 这样的网站使用，以减少数据库访问并显著提高网站性能。</p>\n<p>Memcached 以一个守护进程的形式运行，并且被分配了指定数量的 RAM。它所做的就是提供一个快速接口用于在缓存中添加，检索和删除数据。所有数据都直接存储在内存中，因此不会产生数据库或文件系统使用的开销。</p>\n<p>在安装 Memcached 本身之后，您需要安装一个 Memcached 绑定。有几个 Python Memcached 绑定可用，Django 支持的两个是 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/pylibmc/\">pylibmc</a> 和 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/pymemcache/\">pymemcache</a>。</p>\n<p>在 Django 中使用 Memcached ：</p>\n<ul class=\"simple\">\n<li><p>设置 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 为 <code class=\"docutils literal notranslate\">django.core.cache.backends.memcached.PyMemcacheCache</code> 或 <code class=\"docutils literal notranslate\">django.core.cache.backends.memcached.PyLibMCCache</code> （取决于你选择的 memcached 绑定）。</p></li>\n<li><p>将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 设置为 <code class=\"docutils literal notranslate\">ip:port</code> 值，其中 <code class=\"docutils literal notranslate\">ip</code> 是 Memcached 守护进程的 IP 地址，<code class=\"docutils literal notranslate\">port</code> 是 Memcached 运行的端口，或者设置为 <code class=\"docutils literal notranslate\">unix:path</code> 值，其中 <code class=\"docutils literal notranslate\">path</code> 是 Memcached Unix socket 文件的路径。</p></li>\n</ul>\n<p>在这个例子中，Memcached 运行在 localhost（127.0.0.1）端口 11211，使用 <code class=\"docutils literal notranslate\">pymemcache</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyMemcacheCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;127.0.0.1:11211&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>在这个例子中，Memcached 可以通过本地 Unix 套接字文件 <code class=\"file docutils literal notranslate\">/tmp/memcached.sock</code> 使用 <code class=\"docutils literal notranslate\">pymemcache</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyMemcacheCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;unix:/tmp/memcached.sock&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>Memcached 有一个很好的特性，就是它可以在多台服务器上共享一个缓存。这意味着你可以在多台机器上运行 Memcached 守护进程，程序将把这组机器作为一个 <em>单一</em> 的缓存，而不需要在每台机器上重复缓存值。要利用这个特性，请在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 中包含所有服务器地址，可以是分号或逗号分隔的字符串，也可以是一个列表。</p>\n<p>在这个例子中，缓存是通过运行在 IP 地址 172.19.26.240 和 172.19.26.242 上的 Memcached 实例共享的，这两个实例都在 11211 端口上：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyMemcacheCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n            <span class=\"s2\">&quot;172.19.26.240:11211&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;172.19.26.242:11211&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">],</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>在下面的例子中，缓存是由运行在 IP 地址 172.19.26.240（端口11211）、172.19.26.242（端口11212）和 172.19.26.244（端口11213）上的 Memcached 实例共享的：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyMemcacheCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n            <span class=\"s2\">&quot;172.19.26.240:11211&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;172.19.26.242:11212&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;172.19.26.244:11213&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">],</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>默认情况下，<code class=\"docutils literal notranslate\">PyMemcacheCache</code> 后端设置以下选项（您可以在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-OPTIONS\"><code class=\"xref std std-setting docutils literal notranslate\">OPTIONS</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=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;allow_unicode_keys&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;default_noreply&quot;</span><span class=\"p\">:</span> <span class=\"kc\">False</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;serde&quot;</span><span class=\"p\">:</span> pymemcache<span class=\"o\">.</span>serde<span class=\"o\">.</span>pickle_serde<span class=\"p\">,</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>关于 Memcached 的最后一点是，基于内存的缓存有一个缺点：因为缓存的数据存储在内存中，如果你的服务器崩溃，数据将丢失。显然，内存并不是用来永久存储数据的，所以不要依赖基于内存的缓存作为你唯一的数据存储。毫无疑问，Django 缓存后端中的 <em>每个</em> 都不应该用于永久存储 —— 它们的目的都是为了缓存的解决方案，而不是存储 —— 但我们在这里指出这一点是因为基于内存的缓存是格外临时的。</p>\n</section>\n<section id=\"redis\">\n<span id=\"id4\"></span><h3>Redis<a class=\"heading-anchor\" href=\"#redis\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference external\" href=\"https://redis.io/\">Redis</a> 是一个内存数据库，可用于缓存。要开始使用它，您需要在本地或远程机器上运行一个 Redis 服务器。</p>\n<p>在设置好 Redis 服务器之后，您需要安装 Redis 的 Python 绑定。Django 原生支持的绑定是 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/redis/\">redis-py</a>。同时，建议安装 <a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/hiredis/\">hiredis-py</a> 包。</p>\n<p>要在 Django 中使用 Redis 作为缓存后端：</p>\n<ul class=\"simple\">\n<li><p>将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 设置为 <code class=\"docutils literal notranslate\">django.core.cache.backends.redis.RedisCache</code>。</p></li>\n<li><p>Set <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> to the URL pointing to your Redis\ninstance, using the appropriate scheme. See the <code class=\"docutils literal notranslate\">redis-py</code> docs for\n<a class=\"reference external\" href=\"https://redis.readthedocs.io/en/stable/connections.html#redis.connection.ConnectionPool.from_url\">details on the available schemes</a>.</p></li>\n</ul>\n<p>例如，如果 Redis 在本地主机（127.0.0.1）的端口 6379 上运行：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.redis.RedisCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;redis://127.0.0.1:6379&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>通常，Redis 服务器受到身份验证的保护。为了提供用户名和密码，您可以将它们与 URL 一起添加到 <code class=\"docutils literal notranslate\">LOCATION</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.redis.RedisCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;redis://username:password@127.0.0.1:6379&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>如果您在复制模式下设置了多个 Redis 服务器，可以将这些服务器指定为分号或逗号分隔的字符串，或者作为一个列表。在使用多个服务器时，写操作将在第一个服务器（领导者）上执行，读操作将在随机选择的其他服务器（副本）上执行：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.redis.RedisCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n            <span class=\"s2\">&quot;redis://127.0.0.1:6379&quot;</span><span class=\"p\">,</span>  <span class=\"c1\"># leader</span>\n            <span class=\"s2\">&quot;redis://127.0.0.1:6378&quot;</span><span class=\"p\">,</span>  <span class=\"c1\"># read-replica 1</span>\n            <span class=\"s2\">&quot;redis://127.0.0.1:6377&quot;</span><span class=\"p\">,</span>  <span class=\"c1\"># read-replica 2</span>\n        <span class=\"p\">],</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n</section>\n<section id=\"database-caching\">\n<span id=\"id6\"></span><h3>数据库缓存<a class=\"heading-anchor\" href=\"#database-caching\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django 可以在数据库中存储缓存数据。如果你有一个快速、索引正常的数据库服务器，这种缓存效果最好。</p>\n<p>用数据库表作为你的缓存后端：</p>\n<ul class=\"simple\">\n<li><p>将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 设置为 <code class=\"docutils literal notranslate\">django.core.cache.backends.db.DatabaseCache</code></p></li>\n<li><p>将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 设置为数据库表的 <code class=\"docutils literal notranslate\">tablename</code>。这个表名可以是没有使用过的任何符合要求的名称。</p></li>\n</ul>\n<p>在这个例子中，缓存表的名称是 <code class=\"docutils literal notranslate\">my_cache_table</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.db.DatabaseCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;my_cache_table&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>Unlike other cache backends, the database cache does not support automatic\nculling of expired entries at the database level. Instead, an expired cache\nentry is deleted when evaluated by a <code class=\"docutils literal notranslate\">get()</code> request. Furthermore,\nexpired cache entries are culled when <code class=\"docutils literal notranslate\">add()</code>, <code class=\"docutils literal notranslate\">set()</code>, or <code class=\"docutils literal notranslate\">touch()</code>\nis called and the number of entries exceeds <code class=\"docutils literal notranslate\">MAX_ENTRIES</code>.</p>\n<section id=\"creating-the-cache-table\">\n<span id=\"database-caching-creating-the-table\"></span><h4>创建缓存表<a class=\"heading-anchor\" href=\"#creating-the-cache-table\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>在使用数据库缓存之前，您必须使用以下命令创建缓存表：</p>\n<div class=\"code-block\" data-language=\"shell\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</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=\"Shell code\"><code>python manage.py createcachetable\n</code></pre></div>\n<p>这将在数据库中创建一个表，该表的格式与 Django 数据库缓存系统期望的一致。该表的表名取自 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 。</p>\n<p>如果你正在使用多个数据库缓存， <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/django-admin/#django-admin-createcachetable\"><code class=\"xref std std-djadmin docutils literal notranslate\">createcachetable</code></a> 会为每个缓存创建一个表。</p>\n<p>如果你正在使用多个数据库， <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/django-admin/#django-admin-createcachetable\"><code class=\"xref std std-djadmin docutils literal notranslate\">createcachetable</code></a> 观察你的数据库路由器的 <code class=\"docutils literal notranslate\">allow_migrate()</code> 方法（见下文）。</p>\n<p>像 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> 一样， <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/django-admin/#django-admin-createcachetable\"><code class=\"xref std std-djadmin docutils literal notranslate\">createcachetable</code></a> 不会影响已经存在的表，它只创建缺失的表。</p>\n<p>要打印即将运行的 SQL，而不是运行它，请使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/django-admin/#cmdoption-createcachetable-dry-run\"><code class=\"xref std std-option docutils literal notranslate\">createcachetable --dry-run</code></a> 选项。</p>\n</section>\n<section id=\"multiple-databases\">\n<span id=\"database-caching-multiple-databases\"></span><h4>多数据库<a class=\"heading-anchor\" href=\"#multiple-databases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>如果在多数据库中使用缓存，你也需要设置数据库缓存表的路由指令。因为路由的原因，数据库缓存表在 <code class=\"docutils literal notranslate\">django_cache</code> 应用程序中显示为 <code class=\"docutils literal notranslate\">CacheEntry</code> 的模型名。这个模型不会出现在模型缓存中，但模型详情可用于路由目的。</p>\n<p>比如，下面的路由可以将所有缓存读取操作指向 <code class=\"docutils literal notranslate\">cache_replica</code> ，并且所有的写操作指向 <code class=\"docutils literal notranslate\">cache_primary</code>。缓存表将会只同步到 <code class=\"docutils literal notranslate\">cache_primary</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=\"k\">class</span> <span class=\"nc\">CacheRouter</span><span class=\"p\">:</span>\n    <span class=\"sd\">&quot;&quot;&quot;A router to control all database cache operations&quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_read</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"s2\">&quot;All cache read operations go to the replica&quot;</span>\n        <span class=\"k\">if</span> model<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"o\">==</span> <span class=\"s2\">&quot;django_cache&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s2\">&quot;cache_replica&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">db_for_write</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> model<span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"s2\">&quot;All cache write operations go to primary&quot;</span>\n        <span class=\"k\">if</span> model<span class=\"o\">.</span>_meta<span class=\"o\">.</span>app_label <span class=\"o\">==</span> <span class=\"s2\">&quot;django_cache&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> <span class=\"s2\">&quot;cache_primary&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">allow_migrate</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> db<span class=\"p\">,</span> app_label<span class=\"p\">,</span> model_name<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span>hints<span class=\"p\">):</span>\n        <span class=\"s2\">&quot;Only install the cache model on primary&quot;</span>\n        <span class=\"k\">if</span> app_label <span class=\"o\">==</span> <span class=\"s2\">&quot;django_cache&quot;</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span> db <span class=\"o\">==</span> <span class=\"s2\">&quot;cache_primary&quot;</span>\n        <span class=\"k\">return</span> <span class=\"kc\">None</span>\n</code></pre></div>\n<p>如果你没有指定路由指向数据库缓存模型，缓存后端将使用 <code class=\"docutils literal notranslate\">默认</code> 的数据库。</p>\n<p>如果没使用数据库缓存后端，则无需担心为数据库缓存模型提供路由指令。</p>\n</section>\n</section>\n<section id=\"filesystem-caching\">\n<span id=\"id7\"></span><h3>文件系统缓存<a class=\"heading-anchor\" href=\"#filesystem-caching\"><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/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 设置为 <code class=\"docutils literal notranslate\">&quot;django.core.cache.backends.filebased.FileBasedCache&quot;</code> 并将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 设置为一个合适的路径。比如，在 <code class=\"docutils literal notranslate\">/var/tmp/django_cache</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.filebased.FileBasedCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;/var/tmp/django_cache&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>如果使用 Windows 系统，将驱动器号放在路径开头，如下：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.filebased.FileBasedCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;c:/foo/bar&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>目录路径应该是绝对路径——因此，它应该以文件系统根目录开始。无需担心是否需要以斜杠结尾。</p>\n<p>确保该设置所指向的目录存在，并且具备读写权限，或者可以由您的 Web 服务器运行的系统用户创建。继续上面的示例，如果您的服务器以用户 <code class=\"docutils literal notranslate\">apache</code> 运行，请确保目录 <code class=\"docutils literal notranslate\">/var/tmp/django_cache</code> 存在，并且用户 <code class=\"docutils literal notranslate\">apache</code> 具备读写权限，或者可以由用户 <code class=\"docutils literal notranslate\">apache</code> 创建。</p>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>当缓存 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 包含在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-MEDIA_ROOT\"><code class=\"xref std std-setting docutils literal notranslate\">MEDIA_ROOT</code></a>、 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-STATIC_ROOT\"><code class=\"xref std std-setting docutils literal notranslate\">STATIC_ROOT</code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-STATICFILES_FINDERS\"><code class=\"xref std std-setting docutils literal notranslate\">STATICFILES_FINDERS</code></a> 中，敏感数据可能被暴露。</p>\n<p>获得访问缓存文件的攻击者不仅可以伪造 HTML 内容，你的网站会信任它，而且还可以远程执行任意代码，因为数据是用 <a class=\"reference external\" href=\"https://docs.python.org/3/library/pickle.html#module-pickle\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">pickle</code></a> 序列化的。</p>\n</aside>\n<aside class=\"admonition admonition-warning\" role=\"note\">\n<p class=\"admonition-title\">Warning</p>\n<p>当存储大量文件时，文件系统缓存可能会变得较慢。如果遇到这个问题，考虑使用不同的缓存机制。您还可以子类化 <a class=\"extlink-source reference external\" href=\"https://github.com/django/django/blob/stable/6.1.x/django/core/cache/backends/filebased.py\">FileBasedCache</a> 并改进清除策略。</p>\n</aside>\n</section>\n<section id=\"local-memory-caching\">\n<span id=\"id8\"></span><h3>本地内存缓存<a class=\"heading-anchor\" href=\"#local-memory-caching\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你的配置文件中没有指定其他缓存，那么这是默认的缓存。如果你想获得内存缓存的速度优势，但又不具备运行 Memcached 的能力，可以考虑使用本地内存缓存后端。这个缓存是每进程所有（见下文）和线程安全的。要使用它，可以将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 设置为 <code class=\"docutils literal notranslate\">&quot;django.core.cache.backends.locmem.LocMemCache&quot;</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.locmem.LocMemCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;unique-snowflake&quot;</span><span class=\"p\">,</span>\n    <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/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 被用于标识各个内存存储。如果只有一个 <code class=\"docutils literal notranslate\">locmem</code> 缓存，你可以忽略 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-LOCATION\"><code class=\"xref std std-setting docutils literal notranslate\">LOCATION</code></a> 。但是如果你有多个本地内存缓存，那么你至少要为其中一个起个名字，以便将它们区分开。</p>\n<p>这种缓存使用最近最少使用（LRU）的淘汰策略。</p>\n<p>请注意，每个进程都会有自己的私有缓存实例，这意味着不可能进行跨进程缓存。这也意味着本地内存缓存的内存效率不是特别高，所以对于生产环境来说，它可能不是一个好的选择。对于开发来说是不错的选择。</p>\n</section>\n<section id=\"dummy-caching-for-development\">\n<span id=\"dummy-caching\"></span><h3>虚拟缓存（用于开发模式）<a class=\"heading-anchor\" href=\"#dummy-caching-for-development\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>最后，Django 带有一个实际上不是缓存的 “虚拟” 缓存，它只是实现缓存接口，并不做其他操作。</p>\n<p>如果你有一个生产网站，在不同的地方使用了大量的缓存，但在开发／测试环境中，你不想缓存，也不想单独修改你的代码，那么这就很有用。要激活虚拟缓存，可以像这样设置 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.dummy.DummyCache&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n</section>\n<section id=\"using-a-custom-cache-backend\">\n<span id=\"id9\"></span><h3>使用自定义缓存后端<a class=\"heading-anchor\" href=\"#using-a-custom-cache-backend\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>虽然 Django 内置了对多种缓存后端的支持，但有时你可能希望使用自定义的缓存后端。为了在 Django 中使用外部缓存后端，请将 Python 导入路径作为 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;path.to.backend&quot;</span><span class=\"p\">,</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>如果您正在构建自己的缓存后端，可以使用标准的缓存后端作为参考实现。您可以在 Django 源代码的 <a class=\"extlink-source reference external\" href=\"https://github.com/django/django/blob/stable/6.1.x/django/core/cache/backends/\">django/core/cache/backends/</a> 目录中找到相应的代码。</p>\n<p>注意：除非是令人信服的理由，诸如服务器不支持缓存，否则你应该使用 Django 附带的缓存后端。他们经过了良好的测试并有完整文档。</p>\n</section>\n<section id=\"cache-arguments\">\n<span id=\"id10\"></span><h3>缓存参数<a class=\"heading-anchor\" href=\"#cache-arguments\"><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/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 配置中作为附加键提供。有效参数如下：</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-TIMEOUT\"><code class=\"xref std std-setting docutils literal notranslate\">TIMEOUT</code></a> ：缓存的默认超时时间，以秒为单位。这个参数默认为 <code class=\"docutils literal notranslate\">300</code> 秒（5 分钟）。你可以将 <code class=\"docutils literal notranslate\">TIMEOUT</code> 设置为 <code class=\"docutils literal notranslate\">None</code>，这样，默认情况下，缓存键永远不会过期。值为 <code class=\"docutils literal notranslate\">0</code> 会导致键立即过期（实际上是 “不缓存”）。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-OPTIONS\"><code class=\"xref std std-setting docutils literal notranslate\">OPTIONS</code></a> ：任何应该传递给缓存后端的选项。有效的选项列表会随着每个后端而变化，由第三方库支持的缓存后端会直接将其选项传递给底层缓存库。</p>\n<p>实施自有缓存策略的缓存后端（即 <code class=\"docutils literal notranslate\">locmem</code>、<code class=\"docutils literal notranslate\">filesystem</code> 和 <code class=\"docutils literal notranslate\">database</code> 后端）将尊重以下选项：</p>\n<ul>\n<li><p><code class=\"docutils literal notranslate\">MAX_ENTRIES</code> ：删除旧值之前允许缓存的最大条目。默认是 <code class=\"docutils literal notranslate\">300</code> 。</p></li>\n<li><p><code class=\"docutils literal notranslate\">CULL_FREQUENCY</code> ：当达到 <code class=\"docutils literal notranslate\">MAX_ENTRIES</code> 时，被删除的条目的比例。实际比例是 <code class=\"docutils literal notranslate\">1 / CULL_FREQUENCY</code>，所以将 <code class=\"docutils literal notranslate\">CULL_FREQUENCY</code> 设置为 <code class=\"docutils literal notranslate\">2</code>，即当达到 <code class=\"docutils literal notranslate\">MAX_ENTRIES</code> 时将删除一半的条目。这个参数应该是一个整数，默认为 <code class=\"docutils literal notranslate\">3</code>。</p>\n<p><code class=\"docutils literal notranslate\">CULL_FREQUENCY</code> 的值为 <code class=\"docutils literal notranslate\">0</code> 意味着当达到 <code class=\"docutils literal notranslate\">MAX_ENTRIES</code> 时，整个缓存将被转储。在某些后端（特别是 <code class=\"docutils literal notranslate\">database</code> ），这使得缓存速度 <em>更</em> 快，但代价是缓存未命中更多。</p>\n</li>\n</ul>\n<p>Memcached 和 Redis 后端将 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-OPTIONS\"><code class=\"xref std std-setting docutils literal notranslate\">OPTIONS</code></a> 的内容作为关键字参数传递给客户端构造函数，允许更高级的客户端行为控制。以下是示例用法：</p>\n</li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_PREFIX</code></a>。一个自动包含在 Django 服务器使用的所有缓存键中的字符串（默认为前缀）。</p>\n<p>查看 <a class=\"reference internal\" href=\"#cache-key-prefixing\"><span class=\"std std-ref\">缓存文档</span></a> 获取更多信息。</p>\n</li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-VERSION\"><code class=\"xref std std-setting docutils literal notranslate\">VERSION</code></a> ：Django 服务器生成的缓存键的默认版本号。</p>\n<p>查看 <a class=\"reference internal\" href=\"#cache-versioning\"><span class=\"std std-ref\">缓存文档</span></a> 获取更多信息。</p>\n</li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_FUNCTION\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_FUNCTION</code></a> 一个字符串，包含一个函数的点分隔路径，该函数定义了如何将前缀、版本和键组成一个最终的缓存键。</p>\n<p>查看 <a class=\"reference internal\" href=\"#cache-key-transformation\"><span class=\"std std-ref\">缓存文档</span></a> 获取更多信息。</p>\n</li>\n</ul>\n<p>在本例中，正在配置一个文件系统后端，超时为 60 秒，最大容量 1000 项：</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.filebased.FileBasedCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;/var/tmp/django_cache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;TIMEOUT&quot;</span><span class=\"p\">:</span> <span class=\"mi\">60</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span><span class=\"s2\">&quot;MAX_ENTRIES&quot;</span><span class=\"p\">:</span> <span class=\"mi\">1000</span><span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>下面是一个基于 <code class=\"docutils literal notranslate\">pylibmc</code> 的后端配置的例子，它启用了二进制协议、SASL 认证和 <code class=\"docutils literal notranslate\">ketama</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyLibMCCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;127.0.0.1:11211&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;binary&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;username&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;user&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;password&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;pass&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;behaviors&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n                <span class=\"s2\">&quot;ketama&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n            <span class=\"p\">},</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>下面是一个基于 <code class=\"docutils literal notranslate\">pymemcache</code> 的后端配置实例，它启用了客户端池（通过保持客户端连接来提高性能），将 memcache／网络错误视为缓存失效，并在连接的 socket 上设置了 <code class=\"docutils literal notranslate\">TCP_NODELAY</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.memcached.PyMemcacheCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;127.0.0.1:11211&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;no_delay&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;ignore_exc&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;max_pool_size&quot;</span><span class=\"p\">:</span> <span class=\"mi\">4</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;use_pooling&quot;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n<p>这是一个基于 <code class=\"docutils literal notranslate\">redis</code> 的后端配置示例，它选择数据库 <code class=\"docutils literal notranslate\">10``（默认情况下 Redis 提供 16 个逻辑数据库），并设置自定义的 `connection pool class`_（默认使用 ``redis.ConnectionPool</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>CACHES <span class=\"o\">=</span> <span class=\"p\">{</span>\n    <span class=\"s2\">&quot;default&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n        <span class=\"s2\">&quot;BACKEND&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;django.core.cache.backends.redis.RedisCache&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;LOCATION&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;redis://127.0.0.1:6379&quot;</span><span class=\"p\">,</span>\n        <span class=\"s2\">&quot;OPTIONS&quot;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;db&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;10&quot;</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;pool_class&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;redis.BlockingConnectionPool&quot;</span><span class=\"p\">,</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"the-per-site-cache\">\n<span id=\"id11\"></span><h2>每站点缓存<a class=\"heading-anchor\" href=\"#the-per-site-cache\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>一旦缓存设置完毕，使用缓存最简便的方式就是缓存整个站点。你需要在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\">MIDDLEWARE</code></a> 设置中添加 <code class=\"docutils literal notranslate\">'django.middleware.cache.UpdateCacheMiddleware'</code> 和 <code class=\"docutils literal notranslate\">'django.middleware.cache.FetchFromCacheMiddleware'</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>MIDDLEWARE <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"s2\">&quot;django.middleware.cache.UpdateCacheMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.middleware.common.CommonMiddleware&quot;</span><span class=\"p\">,</span>\n    <span class=\"s2\">&quot;django.middleware.cache.FetchFromCacheMiddleware&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>不，这不是错别字：“update” 中间件必须在列表的第一位，而 “fetch” 中间件必须在最后。细节有点晦涩难懂，但如果你想知道完整的故事，请看下面的 <a class=\"reference internal\" href=\"#order-of-middleware\">中间件的顺序</a> 。</p>\n</aside>\n<p>最后，在 Django 设置文件里添加下面的必需配置：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_ALIAS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_ALIAS</code></a> -- 用于存储的缓存别名。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_SECONDS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_SECONDS</code></a> -- 应缓存每个页面的秒数。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_KEY_PREFIX</code></a> -- 如果使用相同的 Django installation ，通过多站点进行缓存共享，请将此值设置为站点名，或者设置成在Django 实例中唯一的其他字符串，以此防止键冲突。如果你不介意，可以设置成空字符串。</p></li>\n</ul>\n<p>在请求和响应标头允许的情况下，<code class=\"docutils literal notranslate\">FetchFromCacheMiddleware</code> 缓存状态为200的 GET 和 HEAD 响应。对于具有不同查询参数的相同URL的请求的响应被认为是单独的页面，并分别缓存。这个中间件期望一个HEAD请求的响应头与相应的GET请求具有相同的响应头；在这种情况下，它可以为HEAD请求返回一个缓存的GET响应。</p>\n<p>此外，<code class=\"docutils literal notranslate\">UpdateCacheMiddleware</code> 在每个 <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\">HttpResponse</code></a>  里会自动设置一些 headers，这会影响 <a class=\"reference internal\" href=\"#downstream-caches\"><span class=\"std std-ref\">下游缓存</span></a>:</p>\n<ul class=\"simple\">\n<li><p>设置 <code class=\"docutils literal notranslate\">Expires</code> header 为当前日期/时间加上定义的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_SECONDS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_SECONDS</code></a> 。</p></li>\n<li><p>设置  <code class=\"docutils literal notranslate\">Cache-Control</code> header 为缓存页面的最长时间，同样，在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_SECONDS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_SECONDS</code></a> 里设置。</p></li>\n</ul>\n<p>查看 <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/middleware/\"><span class=\"doc\">中间件</span></a> 获取更多中间件信息。</p>\n<p>如果一个视图设置了它自己的缓存过期时间（比如在它的 <code class=\"docutils literal notranslate\">Cache-Control</code> header 里有 <code class=\"docutils literal notranslate\">max-age</code> 部分），然后页面将被缓存起来直到过期，而不是 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_SECONDS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_SECONDS</code></a> 。使用在 <code class=\"docutils literal notranslate\">django.views.decorators.cache</code> 的装饰器，你可以很轻松的设置视图的过期时间（使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/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\">cache_control()</code></a> 装饰器）或者禁用视图缓存（使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.cache.never_cache\" title=\"django.views.decorators.cache.never_cache\"><code class=\"xref py py-func docutils literal notranslate\">never_cache()</code></a> 装饰器）。有关这些装饰器的更多信息，请查看 <a class=\"reference internal\" href=\"#controlling-cache-using-other-headers\">using other headers</a> 部分。</p>\n<p id=\"i18n-cache-key\">If <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-USE_I18N\"><code class=\"xref std std-setting docutils literal notranslate\">USE_I18N</code></a> is set to <code class=\"docutils literal notranslate\">True</code> then the generated cache key will\ninclude the name of the active <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/i18n/#term-language-code\"><span class=\"xref std std-term\">language</span></a> (see also\n<a class=\"reference internal\" href=\"/zh-hans/6.1/topics/i18n/translation/#how-django-discovers-language-preference\"><span class=\"std std-ref\">Django 如何发现语言偏好</span></a>). This allows you to easily\ncache multilingual sites without having to create the cache key yourself.</p>\n<p>当 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-USE_TZ\"><code class=\"xref std std-setting docutils literal notranslate\">USE_TZ</code></a> 被设置为 <code class=\"docutils literal notranslate\">True</code> 时，缓存键也包括 <a class=\"reference internal\" href=\"/zh-hans/6.1/topics/i18n/timezones/#default-current-time-zone\"><span class=\"std std-ref\">当前时区</span></a>。</p>\n</section>\n<section id=\"the-per-view-cache\">\n<h2>视图缓存<a class=\"heading-anchor\" href=\"#the-per-view-cache\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.views.decorators.cache.cache_page\">\n<span class=\"sig-prename descclassname\">django.views.decorators.cache.</span><span class=\"sig-name descname\">cache_page</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">timeout</em>, <em class=\"sig-param\"><span class=\"keyword-only-separator o\"><abbr title=\"Keyword-only parameters separator (PEP 3102)\">*</abbr></span></em>, <em class=\"sig-param\">cache<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">key_prefix<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.views.decorators.cache.cache_page\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>使用缓存框架的通用办法是缓存视图结果。<code class=\"docutils literal notranslate\">django.views.decorators.cache</code> 定义了一个 <code class=\"docutils literal notranslate\">cache_page</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=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> cache_page\n\n\n<span class=\"nd\">@cache_page</span><span class=\"p\">(</span><span class=\"mi\">60</span> <span class=\"o\">*</span> <span class=\"mi\">15</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">cache_page</code> 使用了一个单独的参数：缓存过期时间，以秒为单位。在上面的例子里，<code class=\"docutils literal notranslate\">my_view()</code> 视图的结果将缓存15分钟。（注意，我们用 <code class=\"docutils literal notranslate\">60 * 15</code> 这样的方式编写，目的是方便阅读。 <code class=\"docutils literal notranslate\">60 * 15</code> 将计算为 <code class=\"docutils literal notranslate\">900</code>，也就是15分钟乘以每分钟60秒。）</p>\n<p><code class=\"docutils literal notranslate\">cache_page</code> 设置的缓存超时优先于 <code class=\"docutils literal notranslate\">Cache-Control</code> 头中的 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>max-age'' 指令。</p>\n<p>和缓存站点一样，对视图缓存，以 URL 为键。如果许多 URL 指向相同的视图，每个 URL 将被单独缓存。继续以 <code class=\"docutils literal notranslate\">my_view</code> 为例，如果你的 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>urlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;foo/&lt;int:code&gt;/&quot;</span><span class=\"p\">,</span> my_view<span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>那么 <code class=\"docutils literal notranslate\">/foo/1/</code> 和 <code class=\"docutils literal notranslate\">/foo/23/</code> 的请求将被分别缓存，正如你所料。但一旦部分 URL （比如 <code class=\"docutils literal notranslate\">/foo/23/</code> ）已经被请求，那么随后的请求都将使用缓存。</p>\n<p><code class=\"docutils literal notranslate\">cache_page</code> 也可以传递可选关键字参数 <code class=\"docutils literal notranslate\">cache</code>，它指引装饰器在缓存视图结果时使用特定的缓存（来自 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</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=\"nd\">@cache_page</span><span class=\"p\">(</span><span class=\"mi\">60</span> <span class=\"o\">*</span> <span class=\"mi\">15</span><span class=\"p\">,</span> cache<span class=\"o\">=</span><span class=\"s2\">&quot;special_cache&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>You can also override the cache prefix on a per-view basis. <code class=\"docutils literal notranslate\">cache_page</code>\ntakes an optional keyword argument, <code class=\"docutils literal notranslate\">key_prefix</code>,\nwhich works in the same way as the <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_KEY_PREFIX</code></a>\nsetting for the middleware. It can be used like this:</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\">@cache_page</span><span class=\"p\">(</span><span class=\"mi\">60</span> <span class=\"o\">*</span> <span class=\"mi\">15</span><span class=\"p\">,</span> key_prefix<span class=\"o\">=</span><span class=\"s2\">&quot;site1&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">key_prefix</code> 和 <code class=\"docutils literal notranslate\">cache</code> 参数可能需要被一起指定。<code class=\"docutils literal notranslate\">key_prefix</code> 参数和 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 下指定的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_PREFIX</code></a> 将被连接起来。</p>\n<p>此外， <code class=\"docutils literal notranslate\">cache_page</code> 在响应中自动设置 <code class=\"docutils literal notranslate\">Cache-Control</code> 和 <code class=\"docutils literal notranslate\">Expires</code> 头， 这会影响 <a class=\"reference internal\" href=\"#downstream-caches\"><span class=\"std std-ref\">下游缓存</span></a>.</p>\n<aside class=\"admonition-responses-are-cached-before-response-middleware-runs admonition\" role=\"note\">\n<p class=\"admonition-title\">Responses are cached before response middleware runs</p>\n<p><code class=\"docutils literal notranslate\">cache_page</code> is intended for content that is safe to reuse for requests\nto the same URL. It does not automatically vary by authentication,\nsessions, cookies, or other request-specific state.</p>\n<p>As a decorator wrapping the view directly, responses are cached before\nresponse middleware runs. If cache variation depends on response\nmiddleware, ensure it runs before the response is cached. For example, when\ncaching views containing CSRF-protected forms, follow\n<a class=\"reference internal\" href=\"/zh-hans/6.1/howto/csrf/#csrf-cache-page\"><span class=\"std std-ref\">通过缓存进行 CSRF 防护</span></a> to ensure the <code class=\"docutils literal notranslate\">Vary</code> header is set first.</p>\n</aside>\n<section id=\"specifying-per-view-cache-in-the-urlconf\">\n<h3>在 URLconf 中指定视图缓存<a class=\"heading-anchor\" href=\"#specifying-per-view-cache-in-the-urlconf\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>The examples in the previous section have hardcoded the fact that the view is\ncached, because <code class=\"docutils literal notranslate\">cache_page</code> alters the <code class=\"docutils literal notranslate\">my_view</code> function in place. This\napproach couples your view to the cache system, which is not ideal for several\nreasons. For instance, you might want to reuse the view functions on another,\ncache-less site, or you might want to distribute the views to people who might\nwant to use them without being cached. The solution to these problems is to\nspecify the per-view cache in the URLconf rather than next to the view\nfunctions themselves.</p>\n<p>当你在 URLconf 中使用 <code class=\"docutils literal notranslate\">cache_page</code> 时，可以这样包装视图函数。这是之前提到的 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>urlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;foo/&lt;int:code&gt;/&quot;</span><span class=\"p\">,</span> my_view<span class=\"p\">),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n<p>将 <code class=\"docutils literal notranslate\">my_view</code> 包含在 <code class=\"docutils literal notranslate\">cache_page</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=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> cache_page\n\nurlpatterns <span class=\"o\">=</span> <span class=\"p\">[</span>\n    path<span class=\"p\">(</span><span class=\"s2\">&quot;foo/&lt;int:code&gt;/&quot;</span><span class=\"p\">,</span> cache_page<span class=\"p\">(</span><span class=\"mi\">60</span> <span class=\"o\">*</span> <span class=\"mi\">15</span><span class=\"p\">)(</span>my_view<span class=\"p\">)),</span>\n<span class=\"p\">]</span>\n</code></pre></div>\n</section>\n</section>\n<section id=\"template-fragment-caching\">\n<span id=\"std-templatetag-cache\"></span><h2>模板片段缓存<a class=\"heading-anchor\" href=\"#template-fragment-caching\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果你获得更多的控制，你也可以使用 <code class=\"docutils literal notranslate\">cache</code> 模板标签(tag)来缓存模板片段。要使你的模板能够访问这个标签，请将 <code class=\"docutils literal notranslate\">{% load cache %}</code> 放在模板顶部。</p>\n<p><code class=\"docutils literal notranslate\">{% cache %}</code> 模板标签在给定的时间里缓存片段内容。它需要至少两个参数：缓存时效时间（以秒为单位），缓存片段的名称。如果缓存失效时间被设置为 <code class=\"docutils literal notranslate\">None</code> ，那么片段将被永久缓存。名称不能使变量名。例如：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">cache</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"m\">500</span> <span class=\"nv\">sidebar</span> <span class=\"cp\">%}</span>\n    .. sidebar ..\n<span class=\"cp\">{%</span> <span class=\"k\">endcache</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>Sometimes you might want to cache multiple copies of a fragment depending on\nsome dynamic data that appears inside the fragment. For example, you might want\na separate cached copy of the sidebar used in the previous example for every\nuser of your site. Do this by passing one or more additional arguments, which\nmay be variables with or without filters, to the <code class=\"docutils literal notranslate\">{% cache %}</code> template tag\nthat will uniquely identify the cache fragment when those values are converted\nto strings:</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">cache</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"m\">500</span> <span class=\"nv\">sidebar</span> <span class=\"nv\">request.user.username</span> <span class=\"cp\">%}</span>\n    .. sidebar for logged-in user ..\n<span class=\"cp\">{%</span> <span class=\"k\">endcache</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<aside class=\"admonition-argument-values-converted-to-strings admonition\" role=\"note\">\n<p class=\"admonition-title\">Argument values converted to strings</p>\n<p>Because argument values are converted to strings when creating the cache\nkey, consider uniqueness carefully to avoid serving one fragment for two\ndistinct values that share a string representation, such as <code class=\"docutils literal notranslate\">None</code> and\n<code class=\"docutils literal notranslate\">&quot;None&quot;</code>. Avoid supplying a model instance, since its <code class=\"docutils literal notranslate\">__str__()</code> is\nnot guaranteed to be unique. Conveniently, in the example above,\n<code class=\"docutils literal notranslate\">request.user.username</code> is unique for the default <code class=\"docutils literal notranslate\">User</code> model.</p>\n</aside>\n<p>如果 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-USE_I18N\"><code class=\"xref std std-setting docutils literal notranslate\">USE_I18N</code></a> 被设为 <code class=\"docutils literal notranslate\">True</code>，那么站点中间件缓存将支持多语言（ <span class=\"xref std std-ref\">respect the active language</span> ）。对于 <code class=\"docutils literal notranslate\">cache</code> 模板标签来说，你可以使用模板中可用的特定翻译变量之一（ <span class=\"xref std std-ref\">translation-specific variables</span> ）来达到同样的结果：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">i18n</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">load</span> <span class=\"nv\">cache</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">get_current_language</span> <span class=\"k\">as</span> <span class=\"nv\">LANGUAGE_CODE</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"m\">600</span> <span class=\"nv\">welcome</span> <span class=\"nv\">LANGUAGE_CODE</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">translate</span> <span class=\"s2\">&quot;Welcome to example.com&quot;</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endcache</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>缓存失效时间可以是模板变量，只要模板变量解析为一个整数值即可。例如，如果模板变量 <code class=\"docutils literal notranslate\">my_timeout</code> 被设置成 <code class=\"docutils literal notranslate\">600</code>，那么下面两个例子是一样的：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"m\">600</span> <span class=\"nv\">sidebar</span> <span class=\"cp\">%}</span> ... <span class=\"cp\">{%</span> <span class=\"k\">endcache</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"nv\">my_timeout</span> <span class=\"nv\">sidebar</span> <span class=\"cp\">%}</span> ... <span class=\"cp\">{%</span> <span class=\"k\">endcache</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>这个可以避免在模板中重复。你可以在某处设置缓存失效时间，然后复用这个值。</p>\n<p>默认情况下，缓存标签会先尝试使用名为 &quot;template_fragments&quot; 的缓存。如果这个缓存不存在，它将回退使用默认缓存。你可以选择一个备用缓存后端与 <code class=\"docutils literal notranslate\">using</code> 关键字参数一起使用，这个参数必须是标签的最后一个参数。</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</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=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">cache</span> <span class=\"m\">300</span> <span class=\"nv\">local-thing</span> <span class=\"p\">...</span>  <span class=\"nv\">using</span><span class=\"o\">=</span><span class=\"s2\">&quot;localcache&quot;</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>未设置指定的缓存名称将被视为错误。</p>\n<dl class=\"py function\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.utils.make_template_fragment_key\">\n<span class=\"sig-prename descclassname\">django.core.cache.utils.</span><span class=\"sig-name descname\">make_template_fragment_key</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">fragment_name</em>, <em class=\"sig-param\">vary_on<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.utils.make_template_fragment_key\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>If you want to obtain the cache key used for a cached fragment, you can use\n<code class=\"docutils literal notranslate\">make_template_fragment_key</code>. <code class=\"docutils literal notranslate\">fragment_name</code> is the same as the second\nargument to the <code class=\"docutils literal notranslate\">cache</code> template tag; <code class=\"docutils literal notranslate\">vary_on</code> is a list of all additional\narguments passed to the tag. This function can be useful for invalidating or\noverwriting a cached item, for example:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.cache</span> <span class=\"kn\">import</span> cache\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.cache.utils</span> <span class=\"kn\">import</span> make_template_fragment_key\n<span class=\"go\"># cache key for {% cache 500 sidebar username %}</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>key <span class=\"o\">=</span> make_template_fragment_key<span class=\"p\">(</span><span class=\"s2\">&quot;sidebar&quot;</span><span class=\"p\">,</span> <span class=\"p\">[</span>username<span class=\"p\">])</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>delete<span class=\"p\">(</span>key<span class=\"p\">)</span>  <span class=\"c1\"># invalidates cached template fragment</span>\n<span class=\"go\">True</span>\n</code></pre></div>\n</section>\n<section id=\"the-low-level-cache-api\">\n<span id=\"low-level-cache-api\"></span><h2>底层缓存 API<a class=\"heading-anchor\" href=\"#the-low-level-cache-api\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>有时，缓存整个渲染页面并不会带来太多好处，事实上，这样会很不方便。</p>\n<p>或许，你的站点包含了一个视图，它的结果依赖于许多费时的查询，而且结果会随着时间变化而改变。在这个情况下，使用站点或视图缓存策略提供的全页面缓存并不理想，因为不能缓存所有结果（一些数据经常变动），不过你仍然可以缓存几乎没有变化的结果。</p>\n<p>For cases like this, Django exposes a low-level cache API. You can use this API\nto store objects in the cache with any level of granularity you like. You can\ncache any Python object that can be pickled safely: strings, dictionaries,\nlists of model objects, and so forth. (Most common Python objects can be\npickled; refer to the <a class=\"reference external\" href=\"https://docs.python.org/3/library/pickle.html#module-pickle\" title=\"(in Python v3.14)\"><code class=\"xref py py-mod docutils literal notranslate\">Python documentation</code></a> for more information\nabout pickling.)</p>\n<section id=\"accessing-the-cache\">\n<h3>访问缓存<a class=\"heading-anchor\" href=\"#accessing-the-cache\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<dl class=\"py data\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.caches\">\n<span class=\"sig-prename descclassname\">django.core.cache.</span><span class=\"sig-name descname\">caches</span><a class=\"heading-anchor\" href=\"#django.core.cache.caches\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>你可以通过类似字典一样的  object: <code class=\"docutils literal notranslate\">django.core.cache.caches</code> 对象访问在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 配置的缓存。重复请求同一个线程里的同一个别名将返回同一个对象。</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.cache</span> <span class=\"kn\">import</span> caches\n<span class=\"gp\">&gt;&gt;&gt; </span>cache1 <span class=\"o\">=</span> caches<span class=\"p\">[</span><span class=\"s2\">&quot;myalias&quot;</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache2 <span class=\"o\">=</span> caches<span class=\"p\">[</span><span class=\"s2\">&quot;myalias&quot;</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache1 <span class=\"ow\">is</span> cache2\n<span class=\"go\">True</span>\n</code></pre></div>\n<p>如果键名不存在，将会引发 <code class=\"docutils literal notranslate\">InvalidCacheBackendError</code> 错误。</p>\n<p>为了支持线程安全，将为每个线程返回缓存后端的不同实例。</p>\n</dd></dl>\n\n<dl class=\"py data\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache\">\n<span class=\"sig-prename descclassname\">django.core.cache.</span><span class=\"sig-name descname\">cache</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd><p>作为一种快捷方式，默认缓存可以通过 <code class=\"docutils literal notranslate\">django.core.cache.cache</code> 访问：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span> <span class=\"nn\">django.core.cache</span> <span class=\"kn\">import</span> cache\n</code></pre></div>\n<p>这个对象等价于 <code class=\"docutils literal notranslate\">caches['default']</code> 。</p>\n</dd></dl>\n\n</section>\n<section id=\"basic-usage\">\n<span id=\"cache-basic-interface\"></span><h3>基本用法<a class=\"heading-anchor\" href=\"#basic-usage\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>基本接口是：</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.set\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">set</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">value</em>, <em class=\"sig-param\">timeout<span class=\"o\">=</span><span class=\"default_value\">DEFAULT_TIMEOUT</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.set\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;hello, world!&quot;</span><span class=\"p\">,</span> <span class=\"mi\">30</span><span class=\"p\">)</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.get\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">get</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">default<span class=\"o\">=</span><span class=\"default_value\">None</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.get\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;hello, world!&#39;</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">key</code> 是一个字符串，<code class=\"docutils literal notranslate\">value</code> 可以任何 picklable 形式的 Python 对象。</p>\n<p><code class=\"docutils literal notranslate\">timeout</code> 参数是可选的，默认为 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 中相应后端的 <code class=\"docutils literal notranslate\">timeout</code> 参数。它是值存在缓存里的秒数。<code class=\"docutils literal notranslate\">timeout</code> 设置为 <code class=\"docutils literal notranslate\">None</code> 时将永久缓存。<code class=\"docutils literal notranslate\">timeout</code> 为0将不缓存值。</p>\n<p>如果缓存中不存在该对象，<code class=\"docutils literal notranslate\">cache.get()</code> 返回 <code class=\"docutils literal notranslate\">None</code>：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Wait 30 seconds for &#39;my_key&#39; to expire...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">None</span>\n</code></pre></div>\n<p>如果您需要确定对象是否存在于缓存中，并且您已经存储了字面值 <code class=\"docutils literal notranslate\">None</code>，可以使用一个特殊的对象作为默认值：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>sentinel <span class=\"o\">=</span> <span class=\"nb\">object</span><span class=\"p\">()</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> sentinel<span class=\"p\">)</span> <span class=\"ow\">is</span> sentinel\n<span class=\"go\">False</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Wait 30 seconds for &#39;my_key&#39; to expire...</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> sentinel<span class=\"p\">)</span> <span class=\"ow\">is</span> sentinel\n<span class=\"go\">True</span>\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">cache.get()</code> 可以接受一个 <code class=\"docutils literal notranslate\">default</code> 参数，用于指定在对象不存在于缓存中时返回的值：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;has expired&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;has expired&#39;</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.add\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">add</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">value</em>, <em class=\"sig-param\">timeout<span class=\"o\">=</span><span class=\"default_value\">DEFAULT_TIMEOUT</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.add\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果只在键不存在时才添加键，可以使用 <code class=\"docutils literal notranslate\">add()</code> 方法。它接受与 <code class=\"docutils literal notranslate\">set()</code> 相同的参数，但如果指定的键已经存在，它不会尝试更新缓存：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;add_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Initial value&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>add<span class=\"p\">(</span><span class=\"s2\">&quot;add_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;New value&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;add_key&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;Initial value&#39;</span>\n</code></pre></div>\n<p>如果你想知道通过 <code class=\"docutils literal notranslate\">add()</code> 存储的值是否在缓存中，你可以检查返回值。如果值已保存，将返回 <code class=\"docutils literal notranslate\">True</code> ，否则返回 <code class=\"docutils literal notranslate\">False</code> 。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.get_or_set\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">get_or_set</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">default</em>, <em class=\"sig-param\">timeout<span class=\"o\">=</span><span class=\"default_value\">DEFAULT_TIMEOUT</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.get_or_set\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果要获取键的值，或者如果键不在缓存中则设置一个值，可以使用 <code class=\"docutils literal notranslate\">get_or_set()</code> 方法。它接受与 <code class=\"docutils literal notranslate\">get()</code> 相同的参数，但默认值将作为该键的新缓存值设置，而不是返回值：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_new_key&quot;</span><span class=\"p\">)</span>  <span class=\"c1\"># returns None</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get_or_set<span class=\"p\">(</span><span class=\"s2\">&quot;my_new_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;my new value&quot;</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;my new value&#39;</span>\n</code></pre></div>\n<p>您还可以将任何可调用对象作为 <em>default</em> 值传递：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">datetime</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get_or_set<span class=\"p\">(</span><span class=\"s2\">&quot;some-timestamp-key&quot;</span><span class=\"p\">,</span> datetime<span class=\"o\">.</span>datetime<span class=\"o\">.</span>now<span class=\"p\">)</span>\n<span class=\"go\">datetime.datetime(2014, 12, 11, 0, 15, 49, 457920)</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.get_many\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">get_many</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">keys</em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.get_many\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>还有一个 <code class=\"docutils literal notranslate\">get_many()</code> 接口，只访问缓存一次。<code class=\"docutils literal notranslate\">get_many()</code> 返回一个字典，其中包含您请求的实际存在于缓存中的所有键（且未过期的键）：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;b&quot;</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;c&quot;</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get_many<span class=\"p\">([</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;b&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;c&quot;</span><span class=\"p\">])</span>\n<span class=\"go\">{&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.set_many\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">set_many</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">dict</em>, <em class=\"sig-param\">timeout</em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.set_many\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>要更高效地设置多个值，可以使用 <code class=\"docutils literal notranslate\">set_many()</code> 来传递一个键值对的字典：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set_many<span class=\"p\">({</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">:</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;b&quot;</span><span class=\"p\">:</span> <span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"s2\">&quot;c&quot;</span><span class=\"p\">:</span> <span class=\"mi\">3</span><span class=\"p\">})</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get_many<span class=\"p\">([</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;b&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;c&quot;</span><span class=\"p\">])</span>\n<span class=\"go\">{&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}</span>\n</code></pre></div>\n<p>类似 <code class=\"docutils literal notranslate\">cache.set()</code>，<code class=\"docutils literal notranslate\">set_many()</code> 带有一个可选的 <code class=\"docutils literal notranslate\">timeout</code> 参数。</p>\n<p>在已支持的后端（memcached），<code class=\"docutils literal notranslate\">set_many()</code> 会返回无法插入的键列表。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.delete\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">delete</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.delete\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>您可以使用 <code class=\"docutils literal notranslate\">delete()</code> 明确删除键，以清除特定对象的缓存：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>delete<span class=\"p\">(</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre></div>\n<p>如果键被成功删除，将返回 <code class=\"docutils literal notranslate\">delete()</code> ，否则返回 <code class=\"docutils literal notranslate\">False</code> 。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.delete_many\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">delete_many</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">keys</em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.delete_many\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>If you want to clear a bunch of keys at once, <code class=\"docutils literal notranslate\">delete_many()</code> can take a list\nof keys to be cleared:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>delete_many<span class=\"p\">([</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;b&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;c&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.clear\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">clear</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.clear\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>Finally, if you want to delete all the keys in the cache, use\n<code class=\"docutils literal notranslate\">cache.clear()</code>. Be careful with this; <code class=\"docutils literal notranslate\">clear()</code> will remove <em>everything</em>\nfrom the cache, not just the keys set by your application:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>clear<span class=\"p\">()</span>\n</code></pre></div>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.touch\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">touch</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">timeout<span class=\"o\">=</span><span class=\"default_value\">DEFAULT_TIMEOUT</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.touch\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p><code class=\"docutils literal notranslate\">cache.touch()</code> 设置键的新过期时间。例如，要将键更新为在 10 秒后过期：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>touch<span class=\"p\">(</span><span class=\"s2\">&quot;a&quot;</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre></div>\n<p>和其他方法一样，<code class=\"docutils literal notranslate\">timeout</code> 参数是可选的，并且默认是 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 设置的相应后端的 <code class=\"docutils literal notranslate\">TIMEOUT</code> 选项。</p>\n<p>如果键被成功 <code class=\"docutils literal notranslate\">touch()</code>，将返回 <code class=\"docutils literal notranslate\">True</code>，否则返回 <code class=\"docutils literal notranslate\">False</code>。</p>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.incr\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">incr</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">delta<span class=\"o\">=</span><span class=\"default_value\">1</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.incr\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.decr\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">decr</span><span class=\"sig-paren\">(</span><em class=\"sig-param\">key</em>, <em class=\"sig-param\">delta<span class=\"o\">=</span><span class=\"default_value\">1</span></em>, <em class=\"sig-param\">version<span class=\"o\">=</span><span class=\"default_value\">None</span></em><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.decr\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>您还可以使用 <code class=\"docutils literal notranslate\">incr()</code> 或 <code class=\"docutils literal notranslate\">decr()</code> 方法来递增或递减已存在的键，分别。默认情况下，现有的缓存值将递增或递减 1。可以通过在递增/递减调用中提供参数来指定其他递增/递减的值。如果尝试递增或递减不存在的缓存键，则会引发 ValueError：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>incr<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">2</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>incr<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"go\">12</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>decr<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">11</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>decr<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">)</span>\n<span class=\"go\">6</span>\n</code></pre></div>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>不保证 <code class=\"docutils literal notranslate\">incr()</code> / <code class=\"docutils literal notranslate\">decr()</code> 方法是原子。那些后端支持原子递增/递减（最值得注意的是 memcached 后端），递增和递减操作是原子的。然而，如果后端本身没有提供递增/递减方法，则将使用两步（检索和更新）来实现。</p>\n</aside>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"django.core.cache.cache.close\">\n<span class=\"sig-prename descclassname\">cache.</span><span class=\"sig-name descname\">close</span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"heading-anchor\" href=\"#django.core.cache.cache.close\"><span class=\"visually-hidden\">Link to this definition</span><span aria-hidden=\"true\">#</span></a></dt>\n<dd></dd></dl>\n\n<p>如果缓存后端已经实现了 <code class=\"docutils literal notranslate\">close()</code> 方法，你可以关闭和缓存的连接。</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>close<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>对于没有实现 <code class=\"docutils literal notranslate\">close</code> 方法的缓存，它将无效操作。</p>\n</aside>\n<aside class=\"admonition admonition-note\" role=\"note\">\n<p class=\"admonition-title\">Note</p>\n<p>基本方法的异步变体以 <code class=\"docutils literal notranslate\">a</code> 为前缀，例如 <code class=\"docutils literal notranslate\">cache.aadd()</code> 或 <code class=\"docutils literal notranslate\">cache.adelete_many()</code>。有关更多详细信息，请参阅 <a class=\"reference internal\" href=\"#id16\">异步支持</a>。</p>\n</aside>\n</section>\n<section id=\"cache-key-prefixing\">\n<span id=\"id13\"></span><h3>缓存键前缀<a class=\"heading-anchor\" href=\"#cache-key-prefixing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你正在服务器之间或者生产/开发缓存之间共享缓存实例，有可能会使得一个服务器使用另一个服务器的缓存数据。如果缓存数据格式是相同的，这会导致一些难以诊断的问题。</p>\n<p>为了防止这个问题，Django 为单台服务器提供了为所有缓存键提供前缀的方法。当一个特殊的缓存键被保存或检索时，Django 会为缓存键自动添加 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_PREFIX</code></a> 缓存设置的前缀值。</p>\n<p>要确保每个 Django 实例有不同的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_PREFIX\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_PREFIX</code></a> ，这样就保证缓存值不会发生冲突。</p>\n</section>\n<section id=\"cache-versioning\">\n<span id=\"id14\"></span><h3>缓存版本控制<a class=\"heading-anchor\" href=\"#cache-versioning\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当更改使用缓存值的运行代码时，你可能需要清除任何已存的缓存值。最简单的方法是刷新整个缓存，但这会导致那些仍然有用且有效的缓存值。</p>\n<p>Django 提供更好的方式来指向单个缓存值。Django 缓存框架有一个系统范围的版本标识，需要在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-VERSION\"><code class=\"xref std std-setting docutils literal notranslate\">VERSION</code></a> 缓存配置中指定。这个配置的值将自动与缓存前缀和用户提供的缓存键组合起来获取最终的缓存键。</p>\n<p>默认情况下，任何键请求都会自动包含站点默认的缓存键版本。但是，原始缓存函数都包括一个 <code class=\"docutils literal notranslate\">version</code> 参数，因此您可以指定要设置或获取的特定缓存键版本。例如：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Set version 2 of a cache key</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>set<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;hello world!&quot;</span><span class=\"p\">,</span> version<span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Get the default version (assuming version=1)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">None</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Get version 2 of the same key</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> version<span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;hello world!&#39;</span>\n</code></pre></div>\n<p>可以使用 <code class=\"docutils literal notranslate\">incr_version()</code> 和 <code class=\"docutils literal notranslate\">decr_version()</code> 方法递增和递减特定键的版本。这使得可以将特定键提升到新版本，而不影响其他键。继续我们之前的示例：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># Increment the version of &#39;my_key&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>incr_version<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># The default version still isn&#39;t available</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">None</span>\n<span class=\"go\"># Version 2 isn&#39;t available, either</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> version<span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"go\">None</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># But version 3 *is* available</span>\n<span class=\"gp\">&gt;&gt;&gt; </span>cache<span class=\"o\">.</span>get<span class=\"p\">(</span><span class=\"s2\">&quot;my_key&quot;</span><span class=\"p\">,</span> version<span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"go\">&#39;hello world!&#39;</span>\n</code></pre></div>\n</section>\n<section id=\"cache-key-transformation\">\n<span id=\"id15\"></span><h3>缓存键转换<a class=\"heading-anchor\" href=\"#cache-key-transformation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\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=\"nf\">make_key</span><span class=\"p\">(</span>key<span class=\"p\">,</span> key_prefix<span class=\"p\">,</span> version<span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"s2\">&quot;</span><span class=\"si\">%s</span><span class=\"s2\">:</span><span class=\"si\">%s</span><span class=\"s2\">:</span><span class=\"si\">%s</span><span class=\"s2\">&quot;</span> <span class=\"o\">%</span> <span class=\"p\">(</span>key_prefix<span class=\"p\">,</span> version<span class=\"p\">,</span> key<span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你想用不同方式组合，或者应用其他处理来获得最终键（比如，获得关键部分的哈希摘要），那么你可以提供一个自定义的键函数。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-KEY_FUNCTION\"><code class=\"xref std std-setting docutils literal notranslate\">KEY_FUNCTION</code></a> 缓存设置指定一个与上面的 <code class=\"docutils literal notranslate\">make_key()</code> 原型匹配的函数路径。如果提供，这个自定义键函数将代替默认的键组合函数来使用。</p>\n</section>\n<section id=\"cache-key-warnings\">\n<h3>缓存键警告<a class=\"heading-anchor\" href=\"#cache-key-warnings\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Memcached 作为最常用的缓存后端，不允许缓存键超过250个字符、包含空格或控制字符，并且使用这些键将会导致异常。为了增加代码可移植性和最小惊讶，如果使用会导致 memcached 报错的键，那么其他内置的缓存框架会发出警告（ <code class=\"docutils literal notranslate\">django.core.cache.backends.base.CacheKeyWarning</code> ）。</p>\n<p>如果你正在使用的生产后端能接受更大范围的键（自定义后端或非 memcached 的内置后端），并且在没有警告的情况下使用更广的范围，你可以在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\">INSTALLED_APPS</code></a> 中的 <code class=\"docutils literal notranslate\">management</code> 模块里静默 <code class=\"docutils literal notranslate\">CacheKeyWarning</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\">import</span> <span class=\"nn\">warnings</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">django.core.cache</span> <span class=\"kn\">import</span> CacheKeyWarning\n\nwarnings<span class=\"o\">.</span>simplefilter<span class=\"p\">(</span><span class=\"s2\">&quot;ignore&quot;</span><span class=\"p\">,</span> CacheKeyWarning<span class=\"p\">)</span>\n</code></pre></div>\n<p>如果你想为某个内置的后端提供自定义的键检验逻辑，你可以将其子类化，只覆盖 <code class=\"docutils literal notranslate\">validate_key</code> 方法，并且按照 <code class=\"docutils literal notranslate\">使用自定义缓存后端</code> 的说明操作。比如，想要为 <code class=\"docutils literal notranslate\">locmem</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=\"nn\">django.core.cache.backends.locmem</span> <span class=\"kn\">import</span> LocMemCache\n\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomLocMemCache</span><span class=\"p\">(</span>LocMemCache<span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"nf\">validate_key</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> key<span class=\"p\">):</span>\n        <span class=\"sd\">&quot;&quot;&quot;Custom validation, raising exceptions or warnings as needed.&quot;&quot;&quot;</span>\n        <span class=\"o\">...</span>\n</code></pre></div>\n<p>...然后在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES\"><code class=\"xref std std-setting docutils literal notranslate\">CACHES</code></a> 里的 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHES-BACKEND\"><code class=\"xref std std-setting docutils literal notranslate\">BACKEND</code></a> 部分使用路径导入此类。</p>\n</section>\n</section>\n<section id=\"asynchronous-support\">\n<span id=\"id16\"></span><h2>异步支持<a class=\"heading-anchor\" href=\"#asynchronous-support\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 目前已经有了对异步缓存后端的支持，但尚未支持异步缓存。这将在将来的版本中推出。</p>\n<p><code class=\"docutils literal notranslate\">django.core.cache.backends.base.BaseCache</code> 具有 <a class=\"reference internal\" href=\"#cache-basic-interface\"><span class=\"std std-ref\">所有基本方法</span></a> 的异步变体。按照惯例，所有方法的异步版本都以 <code class=\"docutils literal notranslate\">a</code> 为前缀。默认情况下，这两个变体的参数相同：</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">await</span> cache<span class=\"o\">.</span>aset<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">await</span> cache<span class=\"o\">.</span>ahas_key<span class=\"p\">(</span><span class=\"s2\">&quot;num&quot;</span><span class=\"p\">)</span>\n<span class=\"go\">True</span>\n</code></pre></div>\n</section>\n<section id=\"downstream-caches\">\n<span id=\"id17\"></span><h2>下游缓存<a class=\"heading-anchor\" href=\"#downstream-caches\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>到目前为止，本文档已经专注于缓存您自己的数据。但是，与 web 开发相关的另一种缓存是由 &quot;下游&quot; 缓存执行的。这些是在请求到达您的网站之前，为用户缓存页面的系统。</p>\n<p>下面是一些下游缓存的例子：</p>\n<ul class=\"simple\">\n<li><p>When using HTTP, your <abbr title=\"Internet Service Provider\">ISP</abbr> may cache\ncertain pages, so if you requested a page from <code class=\"docutils literal notranslate\">http://example.com/</code>, your\nISP would send you the page without having to access example.com directly.\nThe maintainers of example.com have no knowledge of this caching; the ISP\nsits between example.com and your web browser, handling all of the caching\ntransparently. Such caching is not possible under HTTPS as it would\nconstitute a man-in-the-middle attack.</p></li>\n<li><p>您的 Django 网站可能会在一个*代理缓存*的后面，例如Squid 网页代理缓存（<a class=\"reference external\" href=\"http://www.squid-cache.org/\">http://www.squid-cache.org/</a>），为了性能而缓存页面。在这种情况下，每个请求首先由代理来处理，只有在需要时才将其传递给应用程序。</p></li>\n<li><p>您的 Web 浏览器也会缓存页面。如果一个网页发送了适当的标头，您的浏览器将在后续请求该页面时使用本地缓存副本，甚至不会再次联系该网页以查看它是否发生了变化。</p></li>\n</ul>\n<p>下游缓存确实可以提高效率，但也存在风险：许多网页的内容根据身份验证和许多其他变量而异，而仅根据 URL 盲目保存页面的缓存系统可能会向随后访问这些页面的访问者公开不正确或敏感的数据。</p>\n<p>For example, if you operate a web email system, then the contents of the\n&quot;inbox&quot; page depend on which user is logged in. If an ISP blindly cached your\nsite, then the first user who logged in through that ISP would have their\nuser-specific inbox page cached for subsequent visitors to the site. That's\nnot cool.</p>\n<p>幸运的是，HTTP 为这个问题提供了解决方案。存在许多 HTTP 报头以指示下游缓存根据指定的变量来区分它们的缓存内容，并且告诉缓存机制不缓存特定的页面。我们将在下面的章节中查看这些标题。</p>\n</section>\n<section id=\"using-vary-headers\">\n<span id=\"id18\"></span><h2>使用 <code class=\"docutils literal notranslate\">Vary</code> 标头<a class=\"heading-anchor\" href=\"#using-vary-headers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p><code class=\"docutils literal notranslate\">Vary</code> 标头定义了缓存机制在构建其缓存键时应考虑哪些请求标头。例如，如果网页的内容取决于用户的语言偏好，那么该页面被称为 &quot;根据语言变化&quot;。</p>\n<p>默认情况下，Django 的缓存系统使用请求的完全合格的URL创建它的缓存密钥——例如，<code class=\"docutils literal notranslate\">&quot;https://www.example.com/stories/2005/?order_by=author&quot;</code>。这意味着对该 URL 的每个请求都将使用相同的缓存版本，而不管用户代理差异（如 cookies 或语言首选项）。但是，如果这个页面基于请求头（如 cookie、语言或用户代理）中的某些差异而产生不同的内容，则需要使用``Vary`` 标头来告诉缓存机制，页面输出取决于这些东西。</p>\n<p>要在 Django 中执行此操作，请使用方便的 <a class=\"reference internal\" href=\"/zh-hans/6.1/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\">django.views.decorators.vary.vary_on_headers()</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=\"kn\">from</span> <span class=\"nn\">django.views.decorators.vary</span> <span class=\"kn\">import</span> vary_on_headers\n\n\n<span class=\"nd\">@vary_on_headers</span><span class=\"p\">(</span><span class=\"s2\">&quot;User-Agent&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>在这里，一个缓存机制（比如 Django 自带的缓存中间件）将为每一个唯一的用户代理缓存一个独立的页面版本。</p>\n<p>使用 <code class=\"docutils literal notranslate\">vary_on_headers</code> 装饰器而不是手动设置 <code class=\"docutils literal notranslate\">Vary</code> 头（使用 <code class=\"docutils literal notranslate\">response.headers['Vary'] = 'user-agent'</code>）的好处是，装饰器 <em>添加</em> 到 <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>Vary `` 头（可能已经存在），而不是从头开始设置，可能会覆盖已经存在的东西。</p>\n<p>你可以传递多个头参数给 <code class=\"docutils literal notranslate\">vary_on_headers()</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\">@vary_on_headers</span><span class=\"p\">(</span><span class=\"s2\">&quot;User-Agent&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;Cookie&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>这告诉下游缓存两者有所不同，意味着每个用户代理和 cookie 的组合将获取它自己的缓存值。比如，一个请求带有用户代理 <code class=\"docutils literal notranslate\">Mozilla</code> 和 cookie 值 <code class=\"docutils literal notranslate\">foo=bar</code> 被认为和用户代理 <code class=\"docutils literal notranslate\">Mozilla</code> 和 cookie 值 <code class=\"docutils literal notranslate\">foo=ham</code> 是不同的。</p>\n<p>因为 cookie 的变化如此普遍，所以这里有个 <a class=\"reference internal\" href=\"/zh-hans/6.1/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\">django.views.decorators.vary.vary_on_cookie()</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=\"nd\">@vary_on_cookie</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n\n\n<span class=\"nd\">@vary_on_headers</span><span class=\"p\">(</span><span class=\"s2\">&quot;Cookie&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>传递给 <code class=\"docutils literal notranslate\">vary_on_headers</code> 的头是不区分大小写的；<code class=\"docutils literal notranslate\">&quot;User-Agent&quot;</code> 和 <code class=\"docutils literal notranslate\">&quot;user-agent&quot;</code> 是一样的。</p>\n<p>你也可以直接使用帮助函数 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/utils/#django.utils.cache.patch_vary_headers\" title=\"django.utils.cache.patch_vary_headers\"><code class=\"xref py py-func docutils literal notranslate\">django.utils.cache.patch_vary_headers()</code></a> 。这个函数可以设置或添加 <code class=\"docutils literal notranslate\">Vary header</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=\"nn\">django.shortcuts</span> <span class=\"kn\">import</span> render\n<span class=\"kn\">from</span> <span class=\"nn\">django.utils.cache</span> <span class=\"kn\">import</span> patch_vary_headers\n\n\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    response <span class=\"o\">=</span> render<span class=\"p\">(</span>request<span class=\"p\">,</span> <span class=\"s2\">&quot;template_name&quot;</span><span class=\"p\">,</span> context<span class=\"p\">)</span>\n    patch_vary_headers<span class=\"p\">(</span>response<span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"s2\">&quot;Cookie&quot;</span><span class=\"p\">])</span>\n    <span class=\"k\">return</span> response\n</code></pre></div>\n<p><code class=\"docutils literal notranslate\">patch_vary_headers</code> 带有一个 <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\">HttpResponse</code></a> 作为它的第一个参数，一个不区分大小写的头名的列表/元组作为它的第二个参数。</p>\n<p>有关更多关于 Vary 标头的信息，请参阅 <span class=\"target\" id=\"index-7\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9110.html#section-12.5.5\"><strong>official Vary spec</strong></a>。</p>\n<aside class=\"admonition-cachemiddleware-varies-on-authorization-automatically admonition\" role=\"note\">\n<p class=\"admonition-title\"><code class=\"docutils literal notranslate\">CacheMiddleware</code> varies on <code class=\"docutils literal notranslate\">Authorization</code> automatically</p>\n<p>Although varying on <code class=\"docutils literal notranslate\">Authorization</code> is not strictly necessary given that\n<span class=\"target\" id=\"index-1\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9111.html#section-3.5\"><strong>RFC 9111 Section 3.5</strong></a> allows caches to avoid reusing authenticated\nresponses, Django's <code class=\"docutils literal notranslate\">CacheMiddleware</code> adds <code class=\"docutils literal notranslate\">Authorization</code> to the\n<code class=\"docutils literal notranslate\">Vary</code> header to simplify construction of cache keys.</p>\n</aside>\n<aside class=\"version-note version-changed\" data-version=\"6.0.6\" role=\"note\">\n<p class=\"version-note-title\">Changed in Django 6.0.6</p><p>Previously, <code class=\"docutils literal notranslate\">UpdateCacheMiddleware</code> did not vary on <code class=\"docutils literal notranslate\">Authorization</code> for\nrequests bearing that header.</p>\n</aside>\n</section>\n<section id=\"controlling-cache-using-other-headers\">\n<h2>使用其他标头控制高速缓存<a class=\"heading-anchor\" href=\"#controlling-cache-using-other-headers\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>缓存的其他问题是数据的隐私和数据应该存储在缓存的级联中的问题。</p>\n<p>用户通常面临两种类型的缓存：他们自己的浏览器缓存（私有缓存）和其服务提供商的缓存（公共缓存）。公共缓存由多个用户使用，由他人控制。这对于敏感数据带来了问题——您不希望例如，您的银行账号号码存储在公共缓存中。因此，Web 应用程序需要一种方法来告诉缓存哪些数据是私有的，哪些是公共的。</p>\n<p>解决方案是指出一个页面的缓存应该是“私有的”。在 Django中，使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/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\">cache_control()</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=\"kn\">from</span> <span class=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> cache_control\n\n\n<span class=\"nd\">@cache_control</span><span class=\"p\">(</span>private<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>这个装饰器负责在场景后面发送适当的 HTTP 头。</p>\n<p>注意，缓存控制设置“私有”和“公共”是互斥的。装饰器确保“公共”指令被移除，如果应该设置“私有”（反之亦然）。这两个指令的一个示例使用将是一个提供私人和公共条目的博客站点。公共条目可以缓存在任何共享缓存上。下面的代码使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/utils/#django.utils.cache.patch_cache_control\" title=\"django.utils.cache.patch_cache_control\"><code class=\"xref py py-func docutils literal notranslate\">patch_cache_control()</code></a>，手动修改缓存控制头的方法（内部调用的是 <a class=\"reference internal\" href=\"/zh-hans/6.1/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\">cache_control()</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=\"kn\">from</span> <span class=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> patch_cache_control\n<span class=\"kn\">from</span> <span class=\"nn\">django.views.decorators.vary</span> <span class=\"kn\">import</span> vary_on_cookie\n\n\n<span class=\"nd\">@vary_on_cookie</span>\n<span class=\"k\">def</span> <span class=\"nf\">list_blog_entries_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span>\n    <span class=\"k\">if</span> request<span class=\"o\">.</span>user<span class=\"o\">.</span>is_anonymous<span class=\"p\">:</span>\n        response <span class=\"o\">=</span> render_only_public_entries<span class=\"p\">()</span>\n        patch_cache_control<span class=\"p\">(</span>response<span class=\"p\">,</span> public<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        response <span class=\"o\">=</span> render_private_and_public_entries<span class=\"p\">(</span>request<span class=\"o\">.</span>user<span class=\"p\">)</span>\n        patch_cache_control<span class=\"p\">(</span>response<span class=\"p\">,</span> private<span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n    <span class=\"k\">return</span> response\n</code></pre></div>\n<p>您还可以以其他方式控制下游缓存（有关 HTTP 缓存的详细信息，请参见 <span class=\"target\" id=\"index-8\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9111.html\"><strong>RFC 9111</strong></a>）。例如，即使您不使用 Django 的服务器端缓存框架，您仍然可以使用 <span class=\"target\" id=\"index-9\"></span><a class=\"rfc reference external\" href=\"https://datatracker.ietf.org/doc/html/rfc9111.html#section-5.2.2.1\"><strong>max-age</strong></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=\"kn\">from</span> <span class=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> cache_control\n\n\n<span class=\"nd\">@cache_control</span><span class=\"p\">(</span>max_age<span class=\"o\">=</span><span class=\"mi\">3600</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">my_view</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n<p>（如果你使用缓存中间件，它已经使用 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-CACHE_MIDDLEWARE_SECONDS\"><code class=\"xref std std-setting docutils literal notranslate\">CACHE_MIDDLEWARE_SECONDS</code></a> 设置的值设置了 <code class=\"docutils literal notranslate\">max-age</code> 。在这个例子里，<a class=\"reference internal\" href=\"/zh-hans/6.1/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\">cache_control()</code></a> 装饰器里自定义的 <code class=\"docutils literal notranslate\">max_age</code> 将被优先使用，头值将被正确合并。）</p>\n<p>任何有效的 <code class=\"docutils literal notranslate\">Cache-Control</code> 响应指令在 <code class=\"docutils literal notranslate\">cache_control()</code> 中是有效的。这里有很多例子：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">no_transform=True</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">must_revalidate=True</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">stale_while_revalidate=num_seconds</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">no_cache=True</code></p></li>\n</ul>\n<p>已知指令的列表在  IANA registry 都能被找到（注意不是所有的都适用于响应）。</p>\n<p>如果你想使用头部来完全禁用缓存，<a class=\"reference internal\" href=\"/zh-hans/6.1/topics/http/decorators/#django.views.decorators.cache.never_cache\" title=\"django.views.decorators.cache.never_cache\"><code class=\"xref py py-func docutils literal notranslate\">never_cache()</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=\"kn\">from</span> <span class=\"nn\">django.views.decorators.cache</span> <span class=\"kn\">import</span> never_cache\n\n\n<span class=\"nd\">@never_cache</span>\n<span class=\"k\">def</span> <span class=\"nf\">myview</span><span class=\"p\">(</span>request<span class=\"p\">):</span> <span class=\"o\">...</span>\n</code></pre></div>\n</section>\n<section id=\"order-of-middleware\">\n<h2><code class=\"docutils literal notranslate\">MIDDLEWARE</code> 顺序<a class=\"heading-anchor\" href=\"#order-of-middleware\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>如果使用缓存中间件，重要的是将每一半放在 <a class=\"reference internal\" href=\"/zh-hans/6.1/ref/settings/#std-setting-MIDDLEWARE\"><code class=\"xref std std-setting docutils literal notranslate\">MIDDLEWARE</code></a> 设置的正确位置。这是因为缓存中间件需要知道哪些头可以改变缓存存储。中间件总是可以在 <code class=\"docutils literal notranslate\">Vary</code> 响应头中添加一些东西。</p>\n<p><code class=\"docutils literal notranslate\">UpdateCacheMiddleware</code> 在响应阶段运行，其中中间件以相反的顺序运行，因此列表顶部的项目在响应阶段的*最后*运行。因此，您需要确保 <code class=\"docutils literal notranslate\">UpdateCacheMiddleware</code> 出现在任何其他可能添加到 <code class=\"docutils literal notranslate\">Vary</code> 标头的其他中间件*之前*。下面的中间件模块类似：</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\">SessionMiddleware</code> 添加 <code class=\"docutils literal notranslate\">Cookie</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">GZipMiddleware</code> 添加 <code class=\"docutils literal notranslate\">Accept-Encoding</code></p></li>\n<li><p><code class=\"docutils literal notranslate\">LocaleMiddleware</code> 添加 <code class=\"docutils literal notranslate\">Accept-Language</code></p></li>\n</ul>\n<p>另一方面，<code class=\"docutils literal notranslate\">FetchFromCacheMiddleware</code> 在请求阶段运行，从头到尾应用中间件，因此列表顶部的条目首先在请求阶段运行。在其他中间件更新 <code class=\"docutils literal notranslate\">Vary</code> 头部后，<code class=\"docutils literal notranslate\">FetchFromCacheMiddleware</code> 也需要运行，因此 <code class=\"docutils literal notranslate\">FetchFromCacheMiddleware</code> 必须在任何条目之后运行。</p>\n</section>","rootId":"django-s-cache-framework","toc":[{"title":"设置缓存","anchor":"setting-up-the-cache","children":[{"title":"Memcached","anchor":"memcached","children":[]},{"title":"Redis","anchor":"redis","children":[]},{"title":"数据库缓存","anchor":"database-caching","children":[{"title":"创建缓存表","anchor":"creating-the-cache-table","children":[]},{"title":"多数据库","anchor":"multiple-databases","children":[]}]},{"title":"文件系统缓存","anchor":"filesystem-caching","children":[]},{"title":"本地内存缓存","anchor":"local-memory-caching","children":[]},{"title":"虚拟缓存（用于开发模式）","anchor":"dummy-caching-for-development","children":[]},{"title":"使用自定义缓存后端","anchor":"using-a-custom-cache-backend","children":[]},{"title":"缓存参数","anchor":"cache-arguments","children":[]}]},{"title":"每站点缓存","anchor":"the-per-site-cache","children":[]},{"title":"视图缓存","anchor":"the-per-view-cache","children":[{"title":"在 URLconf 中指定视图缓存","anchor":"specifying-per-view-cache-in-the-urlconf","children":[]}]},{"title":"模板片段缓存","anchor":"template-fragment-caching","children":[]},{"title":"底层缓存 API","anchor":"the-low-level-cache-api","children":[{"title":"访问缓存","anchor":"accessing-the-cache","children":[]},{"title":"基本用法","anchor":"basic-usage","children":[]},{"title":"缓存键前缀","anchor":"cache-key-prefixing","children":[]},{"title":"缓存版本控制","anchor":"cache-versioning","children":[]},{"title":"缓存键转换","anchor":"cache-key-transformation","children":[]},{"title":"缓存键警告","anchor":"cache-key-warnings","children":[]}]},{"title":"异步支持","anchor":"asynchronous-support","children":[]},{"title":"下游缓存","anchor":"downstream-caches","children":[]},{"title":"使用 Vary 标头","anchor":"using-vary-headers","children":[]},{"title":"使用其他标头控制高速缓存","anchor":"controlling-cache-using-other-headers","children":[]},{"title":"MIDDLEWARE 顺序","anchor":"order-of-middleware","children":[]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/6.1/topics/"}],"prev":{"docname":"topics/auth/customizing","title":"Django 中的自定义验证","url":"/zh-hans/6.1/topics/auth/customizing/"},"next":{"docname":"topics/conditional-view-processing","title":"条件视图处理","url":"/zh-hans/6.1/topics/conditional-view-processing/"},"formats":{"html":"/zh-hans/6.1/topics/cache/","markdown":"/zh-hans/6.1/topics/cache.md","json":"/zh-hans/6.1/topics/cache.json"},"source":"https://github.com/django/django/blob/stable/6.1.x/docs/topics/cache.txt","official":"https://docs.djangoproject.com/zh-hans/6.1/topics/cache/","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"]}