Django 1.8.2.dev20150513143415 documentation

Django’s cache framework

一个动态网站的基本权衡点就是,它是动态的。 每次用户请求页面,服务器会重新计算。从开销处理的角度来看,这比你读取一个现成的标准文件的代价要昂贵的多。

overhead我们的应用不是washingtonpost.com or slashdot.org; 他们只是中小型网站,而且只有那么些流量而已。 但对于中等流量的网站来说,尽可能地减少开销是必要的。

这就是需要缓存的地方

缓存一些东西是为了保存那些需要很多计算资源的结果,这样的话就不必在下次重复消耗计算资源。 下面是一些伪代码,用来解释缓存怎样在动态生成的网页中工作的:

given a URL, try finding that page in the cache
if the page is in the cache:
    return the cached page
else:
    generate the page
    save the generated page in the cache (for next time)
    return the generated page

Django自带了一个健壮的缓存系统来让你保存动态页面这样避免对于每次请求都重新计算。方便起见,Django提供了不同级别的缓存粒度:你可以缓存特定视图的输出、你可以仅仅缓存那些很难生产出来的部分、或者你可以缓存你的整个网站。

Django也能很好的配合那些“下游”缓存, 比如 Squid 和基于浏览器的缓存。这里有一些缓存你不必要直接去控制但是你可以提供线索, (via HTTP headers)关于你的网站哪些部分需要缓存和如何缓存。

See also

The Cache Framework design philosophy explains a few of the design decisions of the framework.

设置缓存

缓存系统需要一些设置才能使用。 也就是说,你必须告诉他你要把数据缓存在哪里- 是数据库中,文件系统或者直接在内存中。 这个决定很重要,因为它会影响你的缓存性能,是的,一些缓存类型要比其他的缓存类型更快速。

你的缓存配置是通过setting 文件的CACHES 配置来实现的。 这里有CACHES所有可配置的变量值。

Memcached

Django支持的最快,最高效的缓存类型, Memcached 是一个全部基于内存的缓存服务,起初是为了解决LiveJournal.com负载来开发的,后来是由Danga开源出来的。 它被类似Facebook 和 维基百科这种网站使用,用来减少数据库访问,显著的提高了网站的性能。

Memcached 是个守护进程,它被分配了单独的内存块。 它做的所有工作就是为缓存提供一个快速的添加,检索,删除的接口。 所有的数据直接存储在内存中,所以它不能取代数据库或者文件系统的使用。

在安装 Memcached 后, 还需要安装 Memcached 依赖模块。Python 有不少Memcache模块最为常用的是python-memcached and pylibmc两个模块.

需要在Django中使用Memcached时:

  • BACKEND 设置为django.core.cache.backends.memcached.MemcachedCache 或者 django.core.cache.backends.memcached.PyLibMCCache (取决于你所选绑定memcached的方式)
  • LOCATION 设置为 ip:port 值,ip 是 Memcached 守护进程的ip地址, port 是Memcached 运行的端口。或者设置为 unix:path 值,path 是 Memcached Unix socket file的路径.

在这个例子中,Memcached 运行在本地(127.0.0.1) 的11211端口,使用python-memcached(也就是需要这么一个python插件) 绑定:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

这个例子中,Memcached 通过一个本地的Unix socket file/tmp/memcached.sock 来交互,也要使用python-memcached绑定:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
    }
}

Memcached有一个非常好的特点就是可以让几个服务的缓存共享。 这就意味着你可以在多台机器上运行Memcached服务,这些程序将会把这几个机器当做 同一个 缓存,从而不需要复制每个缓存的值在每个机器上。为了使用这个特性,把所有的服务地址放在LOCATION里面,用分号隔开或者当做一个list。

这个例子,缓存共享在2个Memcached 实例中,IP地址为172.19.26.240 和 172.19.26.242,端口同为11211:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}

下面的这个例子,缓存通过下面几个  Memcached 实例共享,IP地址为172.19.26.240 (端口 11211), 172.19.26.242 (端口 11212), and 172.19.26.244 (端口 11213):

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11212',
            '172.19.26.244:11213',
        ]
    }
}

关于Memcached最后要说一点,基于内存的缓存有一个缺点:因为缓存数据是存储在内存中的,所以如果你的服务器宕机数据就会丢失。还要明确, 内存不能替代常驻的数据存储,所以不要把基于内存的缓存当成你唯一的数据存储方式。毫无疑问的,没有任何的Django缓存后台应该被用来替代常驻存储--它们要做的是缓存解决方案,而不是存储方案--但是我们在这里指出这一点是因为基于内存的缓存真的是非常的临时。

Database caching

Django 可以把缓存保存在你的数据库里。如果你有一个快速的、专业的数据库服务器的话那这种方式是效果最好的。

为了把数据表用来当做你的缓存后台:

  • BACKEND设置为django.core.cache.backends.db.DatabaseCache
  • LOCATION 设置为 tablename, 数据表的名称。这个名字可以是任何你想要的名字,只要它是一个合法的表名并且在你的数据库中没有被使用过。

在这个示例中,缓存表的名字是 my_cache_table:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

Creating the cache table

使用数据库缓存之前,你必须用这个命令来创建缓存表:

python manage.py createcachetable

这将在你的数据库中创建一个Django的基于数据库缓存系统预期的特定格式的数据表。表名会从 LOCATION中获得。

如果你使用多数据库缓存, createcachetable会在每个缓存中创建一个表。

如果你使用多数据库,createcachetable会遵循你的数据库路由中的allow_migrate()方法(见下)。

migrate, createcachetable 这样的命令不会碰触现有的表。它只创建非现有的表。

Changed in Django 1.7:

在Django 1.7之前, createcachetable一次只创建一个表。You had to pass the name of the table you wanted to create, and if you were using multiple databases, you had to use the --database option. For backwards compatibility, this is still possible.

Multiple databases

如果你在多数据库的情况下使用数据库缓存,你还必须为你的数据库缓存表设置路由说明。出于路由的目的,数据库缓存表会在一个名为 django_cache的应用下的CacheEntrymodel中出现。 这个模型不会出现在模型缓存中,但这个模型的细节可以在路由中使用。

例如, 下面的路由会分配所有缓存读操作到 cache_replica, 和所有写操作到cache_primary. 缓存表只会同步到 cache_primary:

class CacheRouter(object):
    """A router to control all database cache operations"""

    def db_for_read(self, model, **hints):
        "All cache read operations go to the replica"
        if model._meta.app_label == 'django_cache':
            return 'cache_replica'
        return None

    def db_for_write(self, model, **hints):
        "All cache write operations go to primary"
        if model._meta.app_label == 'django_cache':
            return 'cache_primary'
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        "Only install the cache model on primary"
        if app_label == 'django_cache':
            return db == 'cache_primary'
        return None

如果你没有指定路由路径给数据库缓存model,那么缓存就会使用 默认的 数据库。

当然, 如果你不使用数据库做缓存,你就不需要担心提供路由结构给数据库缓存模型。

Filesystem caching

基于文件的缓存后端序列化和存储每个缓存值作为一个单独的文件。 为了使用这个文件缓存,你要设置BACKEND"django.core.cache.backends.filebased.FileBasedCache" 并且 LOCATION 设置为一个合适的目录。例如,把缓存储存在 /var/tmp/django_cache,就用这个设置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}

If you’re on Windows, put the drive letter at the beginning of the path, like this:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'c:/foo/bar',
    }
}

路径应该是绝对路径– 也就是说,要从你的系统路径开始算。你在末尾添加不添加斜杠都是无所谓的。

请确保,你的路径指向是存在的并且,这个路径下 你有系统用户的足够的读,写权限。继续上面的例子,如果你是一个 名叫apache用户,确保 /var/tmp/django_cache这个路径存在并且apache有读和写的权力。

Local-memory caching

这是默认的缓存,如果你不在指定其他的缓存设置。如果你想要具有高速这个有点的基于内存的缓存但是又没有能力带动 Memcached, 那就考虑一下本地缓存吧。This cache is per-process (see below) and thread-safe. To use it, set BACKEND to "django.core.cache.backends.locmem.LocMemCache". For example:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
    }
}

The cache LOCATION is used to identify individual memory stores. If you only have one locmem cache, you can omit the LOCATION; however, if you have more than one local memory cache, you will need to assign a name to at least one of them in order to keep them separate.

Note that each process will have its own private cache instance, which means no cross-process caching is possible. This obviously also means the local memory cache isn’t particularly memory-efficient, so it’s probably not a good choice for production environments. It’s nice for development.

Dummy caching (for development)

最后, Django有一个 “dummy” 缓存,而且还不是真正的缓存– 它只是提供了一个缓存接口,但是什么也不做。

如果你有一个在不同的地方使用高强度缓存的生产环境下的网站,但一个开发/测试环境中,你不想缓存,不希望有你的代码更改为后面的特殊情况,这非常有用。 To activate dummy caching, set BACKEND like so:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
    }
}

Using a custom cache backend

Django包含一定数量的外部缓存后端的支持,有时你可能想要使用一个自定义的缓存后端。 想要使用外部的缓存,就像python import那样在CACHESBACKEND设置中,就像这样

CACHES = {
    'default': {
        'BACKEND': 'path.to.backend',
    }
}

如果你建立自己的缓存后端,你可以使用标准的缓存后端作为参考实现。 You’ll find the code in the django/core/cache/backends/ directory of the Django source.

注意:当没有真正令人信服的原因时,例如不支持它们的主机,您应该坚持Django附带的缓存后端。They’ve been well-tested and are easy to use.

Cache 参数

上述每一个缓存后台都可以给定一些额外的参数来控制缓存行为,这些参数在可以在CACHES setting中以额外键值对的形式给定,可以设置的参数如下:

  • TIMEOUT:缓存的默认过期时间,以秒为单位, 这个参数默认是 300 seconds (5 分钟).

    New in Django 1.7.

    你可以设置TIMEOUTNone 这样的话,缓存默认永远不会过期。值设置成0造成缓存立即失效(缓存就没有意义了)。

  • OPTIONS: 这个参数应该被传到缓存后端。有效的可选项列表根据缓存的后端不同而不同,由第三方库所支持的缓存将会把这些选项直接配置到底层的缓存库。

    缓存的后端实现自己的选择策略 (i.e., the locmem, filesystem and database backends) 将会履行下面这些选项:

    • MAX_ENTRIES:高速缓存允许的最大条目数,超出这个数则旧值将被删除. 这个参数默认是300.

    • CULL_FREQUENCY:当达到MAX_ENTRIES 的时候,被删除的条目比率。 实际比率是 1 / CULL_FREQUENCY, 所以设置CULL_FREQUENCY2会在达到MAX_ENTRIES 所设置值时删去一半的缓存。这个参数应该是整数,默认为 3.

      把 CULL_FREQUENCY的值设置为 0 意味着当达到MAX_ENTRIES时,缓存将被清空。某些缓存后端 (database尤其)这将以很多缓存丢失为代价,大大much 提高接受访问的速度。

  • KEY_PREFIX: A string that will be automatically included (prepended by default) to all cache keys used by the Django server.

    See the cache documentation for more information.

  • VERSION: The default version number for cache keys generated by the Django server.

    See the cache documentation for more information.

  • KEY_FUNCTION A string containing a dotted path to a function that defines how to compose a prefix, version and key into a final cache key.

    See the cache documentation for more information.

在下面这个例子中,一个文件系统缓存后端,缓存过期时间被设置为60秒,最大条目为1000.

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
        'TIMEOUT': 60,
        'OPTIONS': {
            'MAX_ENTRIES': 1000
        }
    }
}

非法的参数会被忽略掉

站点级缓存

一旦高速缓存设置,最简单的方法是使用缓存缓存整个网站。 你需要把'django.middleware.cache.UpdateCacheMiddleware''django.middleware.cache.FetchFromCacheMiddleware' 添加到你的 MIDDLEWARE_CLASSES 设置里, 如例子所示:

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)

Note

不,这里并没有排版错误: 'update'中间件,必须放在列表的开始位置,而fectch中间件,必须放在最后。 细节有点费解,如果您想了解完整内幕请参看下面MIDDLEWARE_CLASSES顺序

然后,添加下面这些需要的参数到settings文件里:

  • CACHE_MIDDLEWARE_ALIAS – 用于存储的缓存的别名
  • CACHE_MIDDLEWARE_SECONDS –每个page需要被缓存多少秒.
  • CACHE_MIDDLEWARE_KEY_PREFIX – 如果缓存被使用相同Django安装的多个网站所共享,那么把这个值设成当前网站名,或其他能代表这个Django实例的唯一字符串,以避免key发生冲突。 如果你不在意的话可以设成空字符串。

FetchFromCacheMiddleware 缓存GET和HEAD状态为200的response(响应),用不同的参数请求相同的url被视为独立的页面,缓存是分开的。This middleware expects that a HEAD request is answered with the same response headers as the corresponding GET request; in which case it can return a cached GET response for HEAD request.

另外, UpdateCacheMiddleware 在每个HttpResponse里自动设置了一些头部信息

  • 设置Last-Modified 当一个新(没缓存的)版本的页面被请求时,为当前日期/时间
  • 设置 Expires 头 为当前日期/时间加上定义的CACHE_MIDDLEWARE_SECONDS.
  • 设置 Cache-Control头部来给页面一个最长的有效期, 来自 CACHE_MIDDLEWARE_SECONDS 的设置.

查看 Middleware 更多中间件.

If a view sets its own cache expiry time (i.e. it has a max-age section in its Cache-Control header) then the page will be cached until the expiry time, rather than CACHE_MIDDLEWARE_SECONDS. Using the decorators in django.views.decorators.cache you can easily set a view’s expiry time (using the cache_control decorator) or disable caching for a view (using the never_cache decorator). See the using other headers section for more on these decorators.

如果USE_I18N设置为True,则生成的缓存key将包含当前(active)起作用的 language的名称-另请参见Django如何发现语言偏好)。This allows you to easily cache multilingual sites without having to create the cache key yourself.

Cache keys also include the active language when USE_L10N is set to True and the current time zone when USE_TZ is set to True.

单个view缓存

django.views.decorators.cache.cache_page()

更加轻巧的缓存框架使用方法是对单个有效视图(views)的输出进行缓存。 django.views.decorators.cache 定义了一个自动缓存视图response(响应)的 cache_page装饰器,使用非常简单:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)
def my_view(request):
    ...

cache_page接受一个参数:timeout,它以秒为单位。在前例中,“my_view()”视图的结果将被缓存 15 分钟 (注意,为了提高可读性我们写了 60 * 15 ——60 * 15 等于 900 ——也就是说15分钟乘以每分种60秒。)

和站点缓存一样,视图缓存与 URL 无关。如果多个 URL 指向同一视图,每个URL将会分别缓存。  继续 my_view范例,如果 URLconf 如下所示:

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', my_view),
]

那么正如你所期待的那样,不同地址(url)的/foo/1//foo/23/的requset 会被分别缓存。但是一旦一个明确的 URL (例如 /foo/23/) 已经被请求过了, 之后再度发出的指向该 URL 的请求将使用缓存。

cache_page 也可以使用一些额外的参数, cache, 指示修饰符去具体使用缓存 (from your CACHES setting) 当要缓存页面结果时。默认地, default cache 会被使用, 但是你可以特别指定你要用的缓存

@cache_page(60 * 15, cache="special_cache")
def my_view(request):
    ...

You can also override the cache prefix on a per-view basis. cache_page takes an optional keyword argument, key_prefix, which works in the same way as the CACHE_MIDDLEWARE_KEY_PREFIX setting for the middleware. It can be used like this:

@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
    ...

key_prefix and cache 参数可以被一起指定。The key_prefix argument and the KEY_PREFIX specified under CACHES will be concatenated.

Specifying per-view cache in the URLconf

前一节中的范例将视图硬编码为使用缓存,因为 cache_page 在适当的位置对 my_view函数进行了转换。 该方法将视图与缓存系统进行了耦合,从几个方面来说并不理想。例如,你可能想在某个无缓存的站点中重用该视图函数,或者不想通过缓存使用页面的人请求你的页面。  解决这些问题的方法是在 URLconf 中指定视图缓存,而不是在这些视图函数上来指定。

Doing so is easy: simply wrap the view function with cache_page when you refer to it in the URLconf. Here’s the old URLconf from earlier:

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', my_view),
]

Here’s the same thing, with my_view wrapped in cache_page:

from django.views.decorators.cache import cache_page

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]

模板片段缓存

如果想对缓存进行更多的控制,可以使用 cache模板标签来缓存模板的一个片段。 要让模板处理这个标签,把{% load cache %} 放在缓存片段的上面。

标签{% cache %}将按给定的时间缓存包含块中的内容。它最少需要两个参数:缓存时间(以秒为单位);给缓存片段起的名称。 The name will be taken as is, do not use a variable. For example:

{% load cache %}
{% cache 500 sidebar %}
    .. sidebar ..
{% endcache %}

有时,你可以依据这个片段内的动态内容缓存多个版本。如上个例子中,可以给站点的每个用户生成不同版本的sidebar缓存。只需要给 {% cache %}标签再传递一个参数来标识区分这个缓存片段。

{% load cache %}
{% cache 500 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

指定一个以上的参数来识别片段是非常好的。 简单的尽可能的传递你需要的参数到 {% cache %}

如果USE_I18N设置为True,则每个站点的中间件缓存将respect the active language对于cache模板标记,您可以使用模板中可用的translation-specific variables之一,以达到相同的结果:

{% load i18n %}
{% load cache %}

{% get_current_language as LANGUAGE_CODE %}

{% cache 600 welcome LANGUAGE_CODE %}
    {% trans "Welcome to example.com" %}
{% endcache %}

The cache timeout can be a template variable, as long as the template variable resolves to an integer value. For example, if the template variable my_timeout is set to the value 600, then the following two examples are equivalent:

{% cache 600 sidebar %} ... {% endcache %}
{% cache my_timeout sidebar %} ... {% endcache %}

This feature is useful in avoiding repetition in templates. You can set the timeout in a variable, in one place, and just reuse that value.

New in Django 1.7:

By default, the cache tag will try to use the cache called “template_fragments”. If no such cache exists, it will fall back to using the default cache. You may select an alternate cache backend to use with the using keyword argument, which must be the last argument to the tag.

{% cache 300 local-thing ...  using="localcache" %}

It is considered an error to specify a cache name that is not configured.

django.core.cache.utils.make_template_fragment_key(fragment_name, vary_on=None)

如果您想获得用于缓存片段缓存键,就可以使用 make_template_fragment_key. fragment_name就跟 cache template tag的第二参数是一样的; vary_on 是一个需要传递额外参数的列表。该功能可以用于无效或覆盖缓存项,例如:

>>> from django.core.cache import cache
>>> from django.core.cache.utils import make_template_fragment_key
# cache key for {% cache 500 sidebar username %}
>>> key = make_template_fragment_key('sidebar', [username])
>>> cache.delete(key) # invalidates cached template fragment

底层的缓存API

有时,缓存整个页面不会让你获益很多,事实上,过度的矫正原来的不方便,变得更加不方便。

也许,例如,您的网站包含的某个view,view返回的结果取决于几个相当占用资源的查询,其返回的结果在不同的时间间隔都有所不同。 在这种情况下,使用“每个站点per-site”或“每个视图per-view”缓存策略提供的全页缓存是不理想的,因为你不想缓存整个结果(因为一些数据经常变化),但你仍然想要缓存很少变化的结果。

对于这个情况 Django提供了一个底层的 cache API. 你可以用这个 API来储存在缓存中的对象,并且控制粒度随你喜欢。您可以缓存可以安全pickle的任何Python对象:模型对象的字符串,字典,列表等等。 (最常见的Python对象可以Pickle;参考Python文档有关pickle更多信息。)

Accessing the cache

django.core.cache.caches
New in Django 1.7.

你可以通过 类字典对象django.core.cache.caches.访问配置在CACHES 设置中的字典类对象。对同一线程相同的别名重复请求将返回相同的对象。

>>> from django.core.cache import caches
>>> cache1 = caches['myalias']
>>> cache2 = caches['myalias']
>>> cache1 is cache2
True

如果key不存在,就会引发一个 InvalidCacheBackendError

为了提供线程安全, 不同的缓存实例将会返回给每一个线程。

django.core.cache.cache

作为一种快捷方式,默认缓存为django.core.cache.cache

>>> from django.core.cache import cache

该对象等效于caches ['default']

django.core.cache.get_cache(backend, **kwargs)

Deprecated since version 1.7: 不推荐使用此功能,而推荐使用caches

在Django 1.7之前,此get_cache函数是获取缓存实例的规范方法。它还可以用于创建具有不同配置的新缓存实例。

>>> from django.core.cache import get_cache
>>> get_cache('default')
>>> get_cache('django.core.cache.backends.memcached.MemcachedCache', LOCATION='127.0.0.2')
>>> get_cache('default', TIMEOUT=300)

基本用法

最基本的接口是 set(key, value, timeout)get(key):

>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
'hello, world!'

这个 timeout 参数是可选的, 默认为 CACHES 设置中所指定的后端(backend)的timeout 参数(如上所述)。 它是你所设置的value(值)将会被储存在缓存中的秒数。如果timeout的返回值是None,那么value的值会永久地保存在缓存中。如果timeout 的值设为 0 ,就不会缓存value值.

如果cache.get()方法要获取的对象在缓存中不存在,则cache.get()返回None

# Wait 30 seconds for 'my_key' to expire...

>>> cache.get('my_key')
None

我们建议不要在缓存中存储文字值“None”,因为您将无法区分存储在缓存中的是“None”值,还是表示缓存中用cache.get()方法未找到目标的返回值None

cache.get()可以采用default(默认)参数。如果要get的对象在缓存中不存在,则返回设置的该default(默认)参数的值:

>>> cache.get('my_key', 'has expired')
'has expired'

要仅添加尚不存在的key(名称),请使用add()方法。It takes the same parameters as set(), but it will not attempt to update the cache if the key specified is already present:

>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'

If you need to know whether add() stored a value in the cache, you can check the return value. It will return True if the value was stored, False otherwise.

There’s also a get_many() interface that only hits the cache once. get_many() returns a dictionary with all the keys you asked for that actually exist in the cache (and haven’t expired):

>>> cache.set('a', 1)
>>> cache.set('b', 2)
>>> cache.set('c', 3)
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}

To set multiple values more efficiently, use set_many() to pass a dictionary of key-value pairs:

>>> cache.set_many({'a': 1, 'b': 2, 'c': 3})
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}

Like cache.set(), set_many() takes an optional timeout parameter.

You can delete keys explicitly with delete(). This is an easy way of clearing the cache for a particular object:

>>> cache.delete('a')

If you want to clear a bunch of keys at once, delete_many() can take a list of keys to be cleared:

>>> cache.delete_many(['a', 'b', 'c'])

Finally, if you want to delete all the keys in the cache, use cache.clear(). Be careful with this; clear() will remove everything from the cache, not just the keys set by your application.

>>> cache.clear()

You can also increment or decrement a key that already exists using the incr() or decr() methods, respectively. By default, the existing cache value will incremented or decremented by 1. Other increment/decrement values can be specified by providing an argument to the increment/decrement call. A ValueError will be raised if you attempt to increment or decrement a nonexistent cache key.:

>>> cache.set('num', 1)
>>> cache.incr('num')
2
>>> cache.incr('num', 10)
12
>>> cache.decr('num')
11
>>> cache.decr('num', 5)
6

Note

incr()/decr() methods are not guaranteed to be atomic. On those backends that support atomic increment/decrement (most notably, the memcached backend), increment and decrement operations will be atomic. However, if the backend doesn’t natively provide an increment/decrement operation, it will be implemented using a two-step retrieve/update.

You can close the connection to your cache with close() if implemented by the cache backend.

>>> cache.close()

Note

For caches that don’t implement close methods it is a no-op.

Cache key prefixing

如果您在服务器之间、或者在您的生产和开发环境之间共享缓存的话,可以使用一台服务器共享另一台服务器缓存的数据。但如果两台服务器缓存的数据格式不同,将会引发一些很难诊断的问题。

为了防止这种情况,Django提供了一个功能,来为所有的服务器使用的 cache keys 添加 prefix (前缀)。当某个指定的 cache key 被保存或检索时,Django将自动为这个 cache key 添加KEY_PREFIX缓存设置中的frefix(前缀)值。

By ensuring each Django instance has a different KEY_PREFIX, you can ensure that there will be no collisions in cache values.

Cache versioning

When you change running code that uses cached values, you may need to purge any existing cached values. The easiest way to do this is to flush the entire cache, but this can lead to the loss of cache values that are still valid and useful.

Django provides a better way to target individual cache values. Django’s cache framework has a system-wide version identifier, specified using the VERSION cache setting. The value of this setting is automatically combined with the cache prefix and the user-provided cache key to obtain the final cache key.

By default, any key request will automatically include the site default cache key version. However, the primitive cache functions all include a version argument, so you can specify a particular cache key version to set or get. For example:

# Set version 2 of a cache key
>>> cache.set('my_key', 'hello world!', version=2)
# Get the default version (assuming version=1)
>>> cache.get('my_key')
None
# Get version 2 of the same key
>>> cache.get('my_key', version=2)
'hello world!'

The version of a specific key can be incremented and decremented using the incr_version() and decr_version() methods. This enables specific keys to be bumped to a new version, leaving other keys unaffected. Continuing our previous example:

# Increment the version of 'my_key'
>>> cache.incr_version('my_key')
# The default version still isn't available
>>> cache.get('my_key')
None
# Version 2 isn't available, either
>>> cache.get('my_key', version=2)
None
# But version 3 *is* available
>>> cache.get('my_key', version=3)
'hello world!'

Cache key transformation

As described in the previous two sections, the cache key provided by a user is not used verbatim – it is combined with the cache prefix and key version to provide a final cache key. By default, the three parts are joined using colons to produce a final string:

def make_key(key, key_prefix, version):
    return ':'.join([key_prefix, str(version), key])

If you want to combine the parts in different ways, or apply other processing to the final key (e.g., taking a hash digest of the key parts), you can provide a custom key function.

The KEY_FUNCTION cache setting specifies a dotted-path to a function matching the prototype of make_key() above. If provided, this custom key function will be used instead of the default key combining function.

Cache key warnings

Memcached, the most commonly-used production cache backend, does not allow cache keys longer than 250 characters or containing whitespace or control characters, and using such keys will cause an exception. To encourage cache-portable code and minimize unpleasant surprises, the other built-in cache backends issue a warning (django.core.cache.backends.base.CacheKeyWarning) if a key is used that would cause an error on memcached.

If you are using a production backend that can accept a wider range of keys (a custom backend, or one of the non-memcached built-in backends), and want to use this wider range without warnings, you can silence CacheKeyWarning with this code in the management module of one of your INSTALLED_APPS:

import warnings

from django.core.cache import CacheKeyWarning

warnings.simplefilter("ignore", CacheKeyWarning)

If you want to instead provide custom key validation logic for one of the built-in backends, you can subclass it, override just the validate_key method, and follow the instructions for using a custom cache backend. For instance, to do this for the locmem backend, put this code in a module:

from django.core.cache.backends.locmem import LocMemCache

class CustomLocMemCache(LocMemCache):
    def validate_key(self, key):
        """Custom validation, raising exceptions or warnings as needed."""
        # ...

...and use the dotted Python path to this class in the BACKEND portion of your CACHES setting.

Downstream caches

So far, this document has focused on caching your own data. But another type of caching is relevant to Web development, too: caching performed by “downstream” caches. These are systems that cache pages for users even before the request reaches your Web site.

Here are a few examples of downstream caches:

  • Your ISP may cache certain pages, so if you requested a page from http://example.com/, your ISP would send you the page without having to access example.com directly. The maintainers of example.com have no knowledge of this caching; the ISP sits between example.com and your Web browser, handling all of the caching transparently.
  • Your Django Web site may sit behind a proxy cache, such as Squid Web Proxy Cache (http://www.squid-cache.org/), that caches pages for performance. In this case, each request first would be handled by the proxy, and it would be passed to your application only if needed.
  • Your Web browser caches pages, too. If a Web page sends out the appropriate headers, your browser will use the local cached copy for subsequent requests to that page, without even contacting the Web page again to see whether it has changed.

Downstream caching is a nice efficiency boost, but there’s a danger to it: Many Web pages’ contents differ based on authentication and a host of other variables, and cache systems that blindly save pages based purely on URLs could expose incorrect or sensitive data to subsequent visitors to those pages.

For example, say you operate a Web email system, and the contents of the “inbox” page obviously depend on which user is logged in. If an ISP blindly cached your site, then the first user who logged in through that ISP would have their user-specific inbox page cached for subsequent visitors to the site. That’s not cool.

Fortunately, HTTP provides a solution to this problem. A number of HTTP headers exist to instruct downstream caches to differ their cache contents depending on designated variables, and to tell caching mechanisms not to cache particular pages. We’ll look at some of these headers in the sections that follow.

Using Vary headers

The Vary header defines which request headers a cache mechanism should take into account when building its cache key. For example, if the contents of a Web page depend on a user’s language preference, the page is said to “vary on language.”

By default, Django’s cache system creates its cache keys using the requested fully-qualified URL – e.g., "http://www.example.com/stories/2005/?order_by=author". This means every request to that URL will use the same cached version, regardless of user-agent differences such as cookies or language preferences. However, if this page produces different content based on some difference in request headers – such as a cookie, or a language, or a user-agent – you’ll need to use the Vary header to tell caching mechanisms that the page output depends on those things.

Changed in Django 1.7:

Cache keys use the request’s fully-qualified URL rather than just the path and query string.

To do this in Django, use the convenient django.views.decorators.vary.vary_on_headers() view decorator, like so:

from django.views.decorators.vary import vary_on_headers

@vary_on_headers('User-Agent')
def my_view(request):
    # ...

In this case, a caching mechanism (such as Django’s own cache middleware) will cache a separate version of the page for each unique user-agent.

The advantage to using the vary_on_headers decorator rather than manually setting the Vary header (using something like response['Vary'] = 'user-agent') is that the decorator adds to the Vary header (which may already exist), rather than setting it from scratch and potentially overriding anything that was already in there.

You can pass multiple headers to vary_on_headers():

@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
    # ...

This tells downstream caches to vary on both, which means each combination of user-agent and cookie will get its own cache value. For example, a request with the user-agent Mozilla and the cookie value foo=bar will be considered different from a request with the user-agent Mozilla and the cookie value foo=ham.

Because varying on cookie is so common, there’s a django.views.decorators.vary.vary_on_cookie() decorator. These two views are equivalent:

@vary_on_cookie
def my_view(request):
    # ...

@vary_on_headers('Cookie')
def my_view(request):
    # ...

The headers you pass to vary_on_headers are not case sensitive; "User-Agent" is the same thing as "user-agent".

You can also use a helper function, django.utils.cache.patch_vary_headers(), directly. This function sets, or adds to, the Vary header. For example:

from django.utils.cache import patch_vary_headers

def my_view(request):
    # ...
    response = render_to_response('template_name', context)
    patch_vary_headers(response, ['Cookie'])
    return response

patch_vary_headers takes an HttpResponse instance as its first argument and a list/tuple of case-insensitive header names as its second argument.

For more on Vary headers, see the official Vary spec.

Controlling cache: Using other headers

Other problems with caching are the privacy of data and the question of where data should be stored in a cascade of caches.

A user usually faces two kinds of caches: their own browser cache (a private cache) and their provider’s cache (a public cache). A public cache is used by multiple users and controlled by someone else. This poses problems with sensitive data–you don’t want, say, your bank account number stored in a public cache. So Web applications need a way to tell caches which data is private and which is public.

The solution is to indicate a page’s cache should be “private.” To do this in Django, use the cache_control view decorator. Example:

from django.views.decorators.cache import cache_control

@cache_control(private=True)
def my_view(request):
    # ...

这个装饰器负责发送相应的HTTP首部。

注意高速缓存控制器的设置"private" 和"public" 是互斥的。装饰器确保:如果设置了“ private”,则删除“ public”指令(反之亦然)。An example use of the two directives would be a blog site that offers both private and public entries. Public entries may be cached on any shared cache. The following code uses django.utils.cache.patch_cache_control(), the manual way to modify the cache control header (it is internally called by the cache_control decorator):

from django.views.decorators.cache import patch_cache_control
from django.views.decorators.vary import vary_on_cookie

@vary_on_cookie
def list_blog_entries_view(request):
    if request.user.is_anonymous():
        response = render_only_public_entries()
        patch_cache_control(response, public=True)
    else:
        response = render_private_and_public_entries(request.user)
        patch_cache_control(response, private=True)

    return response

There are a few other ways to control cache parameters. For example, HTTP allows applications to do the following:

  • Define the maximum time a page should be cached.
  • Specify whether a cache should always check for newer versions, only delivering the cached content when there are no changes. (Some caches might deliver cached content even if the server page changed, simply because the cache copy isn’t yet expired.)

In Django, use the cache_control view decorator to specify these cache parameters. In this example, cache_control tells caches to revalidate the cache on every access and to store cached versions for, at most, 3,600 seconds:

from django.views.decorators.cache import cache_control

@cache_control(must_revalidate=True, max_age=3600)
def my_view(request):
    # ...

Any valid Cache-Control HTTP directive is valid in cache_control(). Here’s a full list:

  • public=True
  • private=True
  • no_cache=True
  • no_transform=True
  • must_revalidate=True
  • proxy_revalidate=True
  • max_age=num_seconds
  • s_maxage=num_seconds

For explanation of Cache-Control HTTP directives, see the Cache-Control spec.

(Note that the caching middleware already sets the cache header’s max-age with the value of the CACHE_MIDDLEWARE_SECONDS setting. If you use a custom max_age in a cache_control decorator, the decorator will take precedence, and the header values will be merged correctly.)

If you want to use headers to disable caching altogether, django.views.decorators.cache.never_cache is a view decorator that adds headers to ensure the response won’t be cached by browsers or other caches. Example:

from django.views.decorators.cache import never_cache

@never_cache
def myview(request):
    # ...

Order of MIDDLEWARE_CLASSES

如果您使用缓存中间件,则必须将 each half 放在 MIDDLEWARE_CLASSES 设置中的正确位置。这是因为缓存中间件需要知道通过哪些headers来更改cache storage。中间件总是尽可能在Vary response header中添加一些内容。

UpdateCacheMiddleware在response阶段运行,而中间件以相反的顺序运行,因此如果某项处于 top of the list,它将会在response阶段的last(最后)运行。因此,您需要确保UpdateCacheMiddleware出现在任何其他可能向Vary header添加内容的中间件之前The following middleware modules do so:

  • SessionMiddleware adds Cookie
  • GZipMiddleware adds Accept-Encoding
  • LocaleMiddleware adds Accept-Language

FetchFromCacheMiddleware, on the other hand, runs during the request phase, where middleware is applied first-to-last, so an item at the top of the list runs first during the request phase. The FetchFromCacheMiddleware also needs to run after other middleware updates the Vary header, so FetchFromCacheMiddleware must be after any item that does so.