mirror of
https://github.com/django/django.git
synced 2024-11-18 15:34:16 +00:00
1293 lines
49 KiB
Plaintext
1293 lines
49 KiB
Plaintext
========================
|
|
Django's cache framework
|
|
========================
|
|
|
|
A fundamental trade-off in dynamic websites is, well, they're dynamic. Each
|
|
time a user requests a page, the Web server makes all sorts of calculations --
|
|
from database queries to template rendering to business logic -- to create the
|
|
page that your site's visitor sees. This is a lot more expensive, from a
|
|
processing-overhead perspective, than your standard
|
|
read-a-file-off-the-filesystem server arrangement.
|
|
|
|
For most Web applications, this overhead isn't a big deal. Most Web
|
|
applications aren't ``washingtonpost.com`` or ``slashdot.org``; they're simply
|
|
small- to medium-sized sites with so-so traffic. But for medium- to
|
|
high-traffic sites, it's essential to cut as much overhead as possible.
|
|
|
|
That's where caching comes in.
|
|
|
|
To cache something is to save the result of an expensive calculation so that
|
|
you don't have to perform the calculation next time. Here's some pseudocode
|
|
explaining how this would work for a dynamically generated Web page::
|
|
|
|
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 comes with a robust cache system that lets you save dynamic pages so
|
|
they don't have to be calculated for each request. For convenience, Django
|
|
offers different levels of cache granularity: You can cache the output of
|
|
specific views, you can cache only the pieces that are difficult to produce,
|
|
or you can cache your entire site.
|
|
|
|
Django also works well with "downstream" caches, such as `Squid
|
|
<http://www.squid-cache.org>`_ and browser-based caches. These are the types of
|
|
caches that you don't directly control but to which you can provide hints (via
|
|
HTTP headers) about which parts of your site should be cached, and how.
|
|
|
|
.. seealso::
|
|
The :ref:`Cache Framework design philosophy <cache-design-philosophy>`
|
|
explains a few of the design decisions of the framework.
|
|
|
|
.. _setting-up-the-cache:
|
|
|
|
Setting up the cache
|
|
====================
|
|
|
|
The cache system requires a small amount of setup. Namely, you have to tell it
|
|
where your cached data should live -- whether in a database, on the filesystem
|
|
or directly in memory. This is an important decision that affects your cache's
|
|
performance; yes, some cache types are faster than others.
|
|
|
|
Your cache preference goes in the :setting:`CACHES` setting in your
|
|
settings file. Here's an explanation of all available values for
|
|
:setting:`CACHES`.
|
|
|
|
.. _memcached:
|
|
|
|
Memcached
|
|
---------
|
|
|
|
The fastest, most efficient type of cache supported natively by Django,
|
|
Memcached__ is an entirely memory-based cache server, originally developed
|
|
to handle high loads at LiveJournal.com and subsequently open-sourced by
|
|
Danga Interactive. It is used by sites such as Facebook and Wikipedia to
|
|
reduce database access and dramatically increase site performance.
|
|
|
|
__ http://memcached.org/
|
|
|
|
Memcached runs as a daemon and is allotted a specified amount of RAM. All it
|
|
does is provide a fast interface for adding, retrieving and deleting data in
|
|
the cache. All data is stored directly in memory, so there's no overhead of
|
|
database or filesystem usage.
|
|
|
|
After installing Memcached itself, you'll need to install a Memcached
|
|
binding. There are several Python Memcached bindings available; the
|
|
two most common are `python-memcached`_ and `pylibmc`_.
|
|
|
|
.. _`python-memcached`: https://pypi.python.org/pypi/python-memcached
|
|
.. _`pylibmc`: https://pypi.python.org/pypi/pylibmc
|
|
|
|
To use Memcached with Django:
|
|
|
|
* Set :setting:`BACKEND <CACHES-BACKEND>` to
|
|
``django.core.cache.backends.memcached.MemcachedCache`` or
|
|
``django.core.cache.backends.memcached.PyLibMCCache`` (depending
|
|
on your chosen memcached binding)
|
|
|
|
* Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values,
|
|
where ``ip`` is the IP address of the Memcached daemon and ``port`` is the
|
|
port on which Memcached is running, or to a ``unix:path`` value, where
|
|
``path`` is the path to a Memcached Unix socket file.
|
|
|
|
In this example, Memcached is running on localhost (127.0.0.1) port 11211, using
|
|
the ``python-memcached`` binding::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
|
'LOCATION': '127.0.0.1:11211',
|
|
}
|
|
}
|
|
|
|
In this example, Memcached is available through a local Unix socket file
|
|
:file:`/tmp/memcached.sock` using the ``python-memcached`` binding::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
|
'LOCATION': 'unix:/tmp/memcached.sock',
|
|
}
|
|
}
|
|
|
|
When using the ``pylibmc`` binding, do not include the ``unix:/`` prefix::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
|
'LOCATION': '/tmp/memcached.sock',
|
|
}
|
|
}
|
|
|
|
One excellent feature of Memcached is its ability to share a cache over
|
|
multiple servers. This means you can run Memcached daemons on multiple
|
|
machines, and the program will treat the group of machines as a *single*
|
|
cache, without the need to duplicate cache values on each machine. To take
|
|
advantage of this feature, include all server addresses in
|
|
:setting:`LOCATION <CACHES-LOCATION>`, either as a semicolon or comma
|
|
delimited string, or as a list.
|
|
|
|
In this example, the cache is shared over Memcached instances running on IP
|
|
address 172.19.26.240 and 172.19.26.242, both on port 11211::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
|
'LOCATION': [
|
|
'172.19.26.240:11211',
|
|
'172.19.26.242:11211',
|
|
]
|
|
}
|
|
}
|
|
|
|
In the following example, the cache is shared over Memcached instances running
|
|
on the IP addresses 172.19.26.240 (port 11211), 172.19.26.242 (port 11212), and
|
|
172.19.26.244 (port 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',
|
|
]
|
|
}
|
|
}
|
|
|
|
A final point about Memcached is that memory-based caching has a
|
|
disadvantage: because the cached data is stored in memory, the data will be
|
|
lost if your server crashes. Clearly, memory isn't intended for permanent data
|
|
storage, so don't rely on memory-based caching as your only data storage.
|
|
Without a doubt, *none* of the Django caching backends should be used for
|
|
permanent storage -- they're all intended to be solutions for caching, not
|
|
storage -- but we point this out here because memory-based caching is
|
|
particularly temporary.
|
|
|
|
.. versionchanged:: 1.11
|
|
|
|
The :setting:`LOCATION <CACHES-LOCATION>` setting now supports defining
|
|
multiple servers as a comma-delimited string.
|
|
|
|
.. _database-caching:
|
|
|
|
Database caching
|
|
----------------
|
|
|
|
Django can store its cached data in your database. This works best if you've
|
|
got a fast, well-indexed database server.
|
|
|
|
To use a database table as your cache backend:
|
|
|
|
* Set :setting:`BACKEND <CACHES-BACKEND>` to
|
|
``django.core.cache.backends.db.DatabaseCache``
|
|
|
|
* Set :setting:`LOCATION <CACHES-LOCATION>` to ``tablename``, the name of the
|
|
database table. This name can be whatever you want, as long as it's a valid
|
|
table name that's not already being used in your database.
|
|
|
|
In this example, the cache table's name is ``my_cache_table``::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
|
|
'LOCATION': 'my_cache_table',
|
|
}
|
|
}
|
|
|
|
Creating the cache table
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Before using the database cache, you must create the cache table with this
|
|
command::
|
|
|
|
python manage.py createcachetable
|
|
|
|
This creates a table in your database that is in the proper format that
|
|
Django's database-cache system expects. The name of the table is taken from
|
|
:setting:`LOCATION <CACHES-LOCATION>`.
|
|
|
|
If you are using multiple database caches, :djadmin:`createcachetable` creates
|
|
one table for each cache.
|
|
|
|
If you are using multiple databases, :djadmin:`createcachetable` observes the
|
|
``allow_migrate()`` method of your database routers (see below).
|
|
|
|
Like :djadmin:`migrate`, :djadmin:`createcachetable` won't touch an existing
|
|
table. It will only create missing tables.
|
|
|
|
To print the SQL that would be run, rather than run it, use the
|
|
:option:`createcachetable --dry-run` option.
|
|
|
|
Multiple databases
|
|
~~~~~~~~~~~~~~~~~~
|
|
|
|
If you use database caching with multiple databases, you'll also need
|
|
to set up routing instructions for your database cache table. For the
|
|
purposes of routing, the database cache table appears as a model named
|
|
``CacheEntry``, in an application named ``django_cache``. This model
|
|
won't appear in the models cache, but the model details can be used
|
|
for routing purposes.
|
|
|
|
For example, the following router would direct all cache read
|
|
operations to ``cache_replica``, and all write operations to
|
|
``cache_primary``. The cache table will only be synchronized onto
|
|
``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
|
|
|
|
If you don't specify routing directions for the database cache model,
|
|
the cache backend will use the ``default`` database.
|
|
|
|
Of course, if you don't use the database cache backend, you don't need
|
|
to worry about providing routing instructions for the database cache
|
|
model.
|
|
|
|
Filesystem caching
|
|
------------------
|
|
|
|
The file-based backend serializes and stores each cache value as a separate
|
|
file. To use this backend set :setting:`BACKEND <CACHES-BACKEND>` to
|
|
``"django.core.cache.backends.filebased.FileBasedCache"`` and
|
|
:setting:`LOCATION <CACHES-LOCATION>` to a suitable directory. For example,
|
|
to store cached data in ``/var/tmp/django_cache``, use this setting::
|
|
|
|
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',
|
|
}
|
|
}
|
|
|
|
The directory path should be absolute -- that is, it should start at the root
|
|
of your filesystem. It doesn't matter whether you put a slash at the end of the
|
|
setting.
|
|
|
|
Make sure the directory pointed-to by this setting exists and is readable and
|
|
writable by the system user under which your Web server runs. Continuing the
|
|
above example, if your server runs as the user ``apache``, make sure the
|
|
directory ``/var/tmp/django_cache`` exists and is readable and writable by the
|
|
user ``apache``.
|
|
|
|
Local-memory caching
|
|
--------------------
|
|
|
|
This is the default cache if another is not specified in your settings file. If
|
|
you want the speed advantages of in-memory caching but don't have the capability
|
|
of running Memcached, consider the local-memory cache backend. This cache is
|
|
per-process (see below) and thread-safe. To use it, set :setting:`BACKEND
|
|
<CACHES-BACKEND>` to ``"django.core.cache.backends.locmem.LocMemCache"``. For
|
|
example::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
|
'LOCATION': 'unique-snowflake',
|
|
}
|
|
}
|
|
|
|
The cache :setting:`LOCATION <CACHES-LOCATION>` is used to identify individual
|
|
memory stores. If you only have one ``locmem`` cache, you can omit the
|
|
:setting:`LOCATION <CACHES-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)
|
|
-------------------------------
|
|
|
|
Finally, Django comes with a "dummy" cache that doesn't actually cache -- it
|
|
just implements the cache interface without doing anything.
|
|
|
|
This is useful if you have a production site that uses heavy-duty caching in
|
|
various places but a development/test environment where you don't want to cache
|
|
and don't want to have to change your code to special-case the latter. To
|
|
activate dummy caching, set :setting:`BACKEND <CACHES-BACKEND>` like so::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
|
|
}
|
|
}
|
|
|
|
Using a custom cache backend
|
|
----------------------------
|
|
|
|
While Django includes support for a number of cache backends out-of-the-box,
|
|
sometimes you might want to use a customized cache backend. To use an external
|
|
cache backend with Django, use the Python import path as the
|
|
:setting:`BACKEND <CACHES-BACKEND>` of the :setting:`CACHES` setting, like so::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'path.to.backend',
|
|
}
|
|
}
|
|
|
|
If you're building your own backend, you can use the standard cache backends
|
|
as reference implementations. You'll find the code in the
|
|
``django/core/cache/backends/`` directory of the Django source.
|
|
|
|
Note: Without a really compelling reason, such as a host that doesn't support
|
|
them, you should stick to the cache backends included with Django. They've
|
|
been well-tested and are easy to use.
|
|
|
|
.. _cache_arguments:
|
|
|
|
Cache arguments
|
|
---------------
|
|
|
|
Each cache backend can be given additional arguments to control caching
|
|
behavior. These arguments are provided as additional keys in the
|
|
:setting:`CACHES` setting. Valid arguments are as follows:
|
|
|
|
* :setting:`TIMEOUT <CACHES-TIMEOUT>`: The default timeout, in
|
|
seconds, to use for the cache. This argument defaults to ``300`` seconds (5 minutes).
|
|
You can set ``TIMEOUT`` to ``None`` so that, by default, cache keys never
|
|
expire. A value of ``0`` causes keys to immediately expire (effectively
|
|
"don't cache").
|
|
|
|
* :setting:`OPTIONS <CACHES-OPTIONS>`: Any options that should be
|
|
passed to the cache backend. The list of valid options will vary
|
|
with each backend, and cache backends backed by a third-party library
|
|
will pass their options directly to the underlying cache library.
|
|
|
|
Cache backends that implement their own culling strategy (i.e.,
|
|
the ``locmem``, ``filesystem`` and ``database`` backends) will
|
|
honor the following options:
|
|
|
|
* ``MAX_ENTRIES``: The maximum number of entries allowed in
|
|
the cache before old values are deleted. This argument
|
|
defaults to ``300``.
|
|
|
|
* ``CULL_FREQUENCY``: The fraction of entries that are culled
|
|
when ``MAX_ENTRIES`` is reached. The actual ratio is
|
|
``1 / CULL_FREQUENCY``, so set ``CULL_FREQUENCY`` to ``2`` to
|
|
cull half the entries when ``MAX_ENTRIES`` is reached. This argument
|
|
should be an integer and defaults to ``3``.
|
|
|
|
A value of ``0`` for ``CULL_FREQUENCY`` means that the
|
|
entire cache will be dumped when ``MAX_ENTRIES`` is reached.
|
|
On some backends (``database`` in particular) this makes culling *much*
|
|
faster at the expense of more cache misses.
|
|
|
|
Memcached backends pass the contents of :setting:`OPTIONS <CACHES-OPTIONS>`
|
|
as keyword arguments to the client constructors, allowing for more advanced
|
|
control of client behavior. For example usage, see below.
|
|
|
|
* :setting:`KEY_PREFIX <CACHES-KEY_PREFIX>`: A string that will be
|
|
automatically included (prepended by default) to all cache keys
|
|
used by the Django server.
|
|
|
|
See the :ref:`cache documentation <cache_key_prefixing>` for
|
|
more information.
|
|
|
|
* :setting:`VERSION <CACHES-VERSION>`: The default version number
|
|
for cache keys generated by the Django server.
|
|
|
|
See the :ref:`cache documentation <cache_versioning>` for more
|
|
information.
|
|
|
|
* :setting:`KEY_FUNCTION <CACHES-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 :ref:`cache documentation <cache_key_transformation>`
|
|
for more information.
|
|
|
|
In this example, a filesystem backend is being configured with a timeout
|
|
of 60 seconds, and a maximum capacity of 1000 items::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
|
|
'LOCATION': '/var/tmp/django_cache',
|
|
'TIMEOUT': 60,
|
|
'OPTIONS': {
|
|
'MAX_ENTRIES': 1000
|
|
}
|
|
}
|
|
}
|
|
|
|
Here's an example configuration for a ``python-memcached`` based backend with
|
|
an object size limit of 2MB::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
|
'LOCATION': '127.0.0.1:11211',
|
|
'OPTIONS': {
|
|
'server_max_value_length': 1024 * 1024 * 2,
|
|
}
|
|
}
|
|
}
|
|
|
|
Here's an example configuration for a ``pylibmc`` based backend that enables
|
|
the binary protocol, SASL authentication, and the ``ketama`` behavior mode::
|
|
|
|
CACHES = {
|
|
'default': {
|
|
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
|
|
'LOCATION': '127.0.0.1:11211',
|
|
'OPTIONS': {
|
|
'binary': True,
|
|
'username': 'user',
|
|
'password': 'pass',
|
|
'behaviors': {
|
|
'ketama': True,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.. versionchanged:: 1.11
|
|
|
|
Memcached backends can now be configured using ``OPTIONS``.
|
|
|
|
In older versions, you could pass ``pylibmc`` behavior settings directly
|
|
inside ``OPTIONS``. This is deprecated in favor of setting them under a
|
|
``behaviors`` key within ``OPTIONS`` instead.
|
|
|
|
.. _the-per-site-cache:
|
|
|
|
The per-site cache
|
|
==================
|
|
|
|
Once the cache is set up, the simplest way to use caching is to cache your
|
|
entire site. You'll need to add
|
|
``'django.middleware.cache.UpdateCacheMiddleware'`` and
|
|
``'django.middleware.cache.FetchFromCacheMiddleware'`` to your
|
|
:setting:`MIDDLEWARE` setting, as in this example::
|
|
|
|
MIDDLEWARE = [
|
|
'django.middleware.cache.UpdateCacheMiddleware',
|
|
'django.middleware.common.CommonMiddleware',
|
|
'django.middleware.cache.FetchFromCacheMiddleware',
|
|
]
|
|
|
|
.. note::
|
|
|
|
No, that's not a typo: the "update" middleware must be first in the list,
|
|
and the "fetch" middleware must be last. The details are a bit obscure, but
|
|
see `Order of MIDDLEWARE`_ below if you'd like the full story.
|
|
|
|
Then, add the following required settings to your Django settings file:
|
|
|
|
* :setting:`CACHE_MIDDLEWARE_ALIAS` -- The cache alias to use for storage.
|
|
* :setting:`CACHE_MIDDLEWARE_SECONDS` -- The number of seconds each page should
|
|
be cached.
|
|
* :setting:`CACHE_MIDDLEWARE_KEY_PREFIX` -- If the cache is shared across
|
|
multiple sites using the same Django installation, set this to the name of
|
|
the site, or some other string that is unique to this Django instance, to
|
|
prevent key collisions. Use an empty string if you don't care.
|
|
|
|
``FetchFromCacheMiddleware`` caches GET and HEAD responses with status 200,
|
|
where the request and response headers allow. Responses to requests for the same
|
|
URL with different query parameters are considered to be unique pages and are
|
|
cached separately. 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.
|
|
|
|
Additionally, ``UpdateCacheMiddleware`` automatically sets a few headers in each
|
|
:class:`~django.http.HttpResponse`:
|
|
|
|
* Sets the ``Expires`` header to the current date/time plus the defined
|
|
:setting:`CACHE_MIDDLEWARE_SECONDS`.
|
|
|
|
* Sets the ``Cache-Control`` header to give a max age for the page --
|
|
again, from the :setting:`CACHE_MIDDLEWARE_SECONDS` setting.
|
|
|
|
.. versionchanged:: 1.11
|
|
|
|
In older versions, the ``Last-Modified`` header was also set.
|
|
|
|
See :doc:`/topics/http/middleware` for more on 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 :setting:`CACHE_MIDDLEWARE_SECONDS`. Using the decorators in
|
|
``django.views.decorators.cache`` you can easily set a view's expiry time
|
|
(using the :func:`~django.views.decorators.cache.cache_control` decorator) or
|
|
disable caching for a view (using the
|
|
:func:`~django.views.decorators.cache.never_cache` decorator). See the
|
|
`using other headers`__ section for more on these decorators.
|
|
|
|
.. _i18n-cache-key:
|
|
|
|
If :setting:`USE_I18N` is set to ``True`` then the generated cache key will
|
|
include the name of the active :term:`language<language code>` -- see also
|
|
:ref:`how-django-discovers-language-preference`). This allows you to easily
|
|
cache multilingual sites without having to create the cache key yourself.
|
|
|
|
Cache keys also include the active :term:`language <language code>` when
|
|
:setting:`USE_L10N` is set to ``True`` and the :ref:`current time zone
|
|
<default-current-time-zone>` when :setting:`USE_TZ` is set to ``True``.
|
|
|
|
__ `Controlling cache: Using other headers`_
|
|
|
|
The per-view cache
|
|
==================
|
|
|
|
.. function:: django.views.decorators.cache.cache_page
|
|
|
|
A more granular way to use the caching framework is by caching the output of
|
|
individual views. ``django.views.decorators.cache`` defines a ``cache_page``
|
|
decorator that will automatically cache the view's response for you. It's easy
|
|
to use::
|
|
|
|
from django.views.decorators.cache import cache_page
|
|
|
|
@cache_page(60 * 15)
|
|
def my_view(request):
|
|
...
|
|
|
|
``cache_page`` takes a single argument: the cache timeout, in seconds. In the
|
|
above example, the result of the ``my_view()`` view will be cached for 15
|
|
minutes. (Note that we've written it as ``60 * 15`` for the purpose of
|
|
readability. ``60 * 15`` will be evaluated to ``900`` -- that is, 15 minutes
|
|
multiplied by 60 seconds per minute.)
|
|
|
|
The per-view cache, like the per-site cache, is keyed off of the URL. If
|
|
multiple URLs point at the same view, each URL will be cached separately.
|
|
Continuing the ``my_view`` example, if your URLconf looks like this::
|
|
|
|
urlpatterns = [
|
|
url(r'^foo/([0-9]{1,2})/$', my_view),
|
|
]
|
|
|
|
then requests to ``/foo/1/`` and ``/foo/23/`` will be cached separately, as
|
|
you may expect. But once a particular URL (e.g., ``/foo/23/``) has been
|
|
requested, subsequent requests to that URL will use the cache.
|
|
|
|
``cache_page`` can also take an optional keyword argument, ``cache``,
|
|
which directs the decorator to use a specific cache (from your
|
|
:setting:`CACHES` setting) when caching view results. By default, the
|
|
``default`` cache will be used, but you can specify any cache you
|
|
want::
|
|
|
|
@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 :setting:`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):
|
|
...
|
|
|
|
The ``key_prefix`` and ``cache`` arguments may be specified together. The
|
|
``key_prefix`` argument and the :setting:`KEY_PREFIX <CACHES-KEY_PREFIX>`
|
|
specified under :setting:`CACHES` will be concatenated.
|
|
|
|
Specifying per-view cache in the URLconf
|
|
----------------------------------------
|
|
|
|
The examples in the previous section have hard-coded the fact that the view is
|
|
cached, because ``cache_page`` alters the ``my_view`` function in place. This
|
|
approach couples your view to the cache system, which is not ideal for several
|
|
reasons. For instance, you might want to reuse the view functions on another,
|
|
cache-less site, or you might want to distribute the views to people who might
|
|
want to use them without being cached. The solution to these problems is to
|
|
specify the per-view cache in the URLconf rather than next to the view functions
|
|
themselves.
|
|
|
|
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)),
|
|
]
|
|
|
|
.. templatetag:: cache
|
|
|
|
Template fragment caching
|
|
=========================
|
|
|
|
If you're after even more control, you can also cache template fragments using
|
|
the ``cache`` template tag. To give your template access to this tag, put
|
|
``{% load cache %}`` near the top of your template.
|
|
|
|
The ``{% cache %}`` template tag caches the contents of the block for a given
|
|
amount of time. It takes at least two arguments: the cache timeout, in seconds,
|
|
and the name to give the cache fragment. The name will be taken as is, do not
|
|
use a variable. For example:
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% load cache %}
|
|
{% cache 500 sidebar %}
|
|
.. sidebar ..
|
|
{% endcache %}
|
|
|
|
Sometimes you might want to cache multiple copies of a fragment depending on
|
|
some dynamic data that appears inside the fragment. For example, you might want a
|
|
separate cached copy of the sidebar used in the previous example for every user
|
|
of your site. Do this by passing additional arguments to the ``{% cache %}``
|
|
template tag to uniquely identify the cache fragment:
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% load cache %}
|
|
{% cache 500 sidebar request.user.username %}
|
|
.. sidebar for logged in user ..
|
|
{% endcache %}
|
|
|
|
It's perfectly fine to specify more than one argument to identify the fragment.
|
|
Simply pass as many arguments to ``{% cache %}`` as you need.
|
|
|
|
If :setting:`USE_I18N` is set to ``True`` the per-site middleware cache will
|
|
:ref:`respect the active language<i18n-cache-key>`. For the ``cache`` template
|
|
tag you could use one of the
|
|
:ref:`translation-specific variables<template-translation-vars>` available in
|
|
templates to achieve the same result:
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% 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:
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% 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.
|
|
|
|
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.
|
|
|
|
.. code-block:: html+django
|
|
|
|
{% cache 300 local-thing ... using="localcache" %}
|
|
|
|
It is considered an error to specify a cache name that is not configured.
|
|
|
|
.. function:: django.core.cache.utils.make_template_fragment_key(fragment_name, vary_on=None)
|
|
|
|
If you want to obtain the cache key used for a cached fragment, you can use
|
|
``make_template_fragment_key``. ``fragment_name`` is the same as second argument
|
|
to the ``cache`` template tag; ``vary_on`` is a list of all additional arguments
|
|
passed to the tag. This function can be useful for invalidating or overwriting
|
|
a cached item, for example:
|
|
|
|
.. code-block:: pycon
|
|
|
|
>>> 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
|
|
|
|
|
|
The low-level cache API
|
|
=======================
|
|
|
|
.. highlight:: python
|
|
|
|
Sometimes, caching an entire rendered page doesn't gain you very much and is,
|
|
in fact, inconvenient overkill.
|
|
|
|
Perhaps, for instance, your site includes a view whose results depend on
|
|
several expensive queries, the results of which change at different intervals.
|
|
In this case, it would not be ideal to use the full-page caching that the
|
|
per-site or per-view cache strategies offer, because you wouldn't want to
|
|
cache the entire result (since some of the data changes often), but you'd still
|
|
want to cache the results that rarely change.
|
|
|
|
For cases like this, Django exposes a simple, low-level cache API. You can use
|
|
this API to store objects in the cache with any level of granularity you like.
|
|
You can cache any Python object that can be pickled safely: strings,
|
|
dictionaries, lists of model objects, and so forth. (Most common Python objects
|
|
can be pickled; refer to the Python documentation for more information about
|
|
pickling.)
|
|
|
|
Accessing the cache
|
|
-------------------
|
|
|
|
.. data:: django.core.cache.caches
|
|
|
|
You can access the caches configured in the :setting:`CACHES` setting
|
|
through a dict-like object: ``django.core.cache.caches``. Repeated
|
|
requests for the same alias in the same thread will return the same
|
|
object.
|
|
|
|
>>> from django.core.cache import caches
|
|
>>> cache1 = caches['myalias']
|
|
>>> cache2 = caches['myalias']
|
|
>>> cache1 is cache2
|
|
True
|
|
|
|
If the named key does not exist, ``InvalidCacheBackendError`` will be
|
|
raised.
|
|
|
|
To provide thread-safety, a different instance of the cache backend will
|
|
be returned for each thread.
|
|
|
|
.. data:: django.core.cache.cache
|
|
|
|
As a shortcut, the default cache is available as
|
|
``django.core.cache.cache``::
|
|
|
|
>>> from django.core.cache import cache
|
|
|
|
This object is equivalent to ``caches['default']``.
|
|
|
|
Basic usage
|
|
-----------
|
|
|
|
The basic interface is ``set(key, value, timeout)`` and ``get(key)``::
|
|
|
|
>>> cache.set('my_key', 'hello, world!', 30)
|
|
>>> cache.get('my_key')
|
|
'hello, world!'
|
|
|
|
``key`` should be a ``str`` (or ``unicode`` on Python 2), and ``value`` can be
|
|
any picklable Python object.
|
|
|
|
The ``timeout`` argument is optional and defaults to the ``timeout`` argument
|
|
of the appropriate backend in the :setting:`CACHES` setting (explained above).
|
|
It's the number of seconds the value should be stored in the cache. Passing in
|
|
``None`` for ``timeout`` will cache the value forever. A ``timeout`` of ``0``
|
|
won't cache the value.
|
|
|
|
If the object doesn't exist in the cache, ``cache.get()`` returns ``None``::
|
|
|
|
>>> # Wait 30 seconds for 'my_key' to expire...
|
|
>>> cache.get('my_key')
|
|
None
|
|
|
|
We advise against storing the literal value ``None`` in the cache, because you
|
|
won't be able to distinguish between your stored ``None`` value and a cache
|
|
miss signified by a return value of ``None``.
|
|
|
|
``cache.get()`` can take a ``default`` argument. This specifies which value to
|
|
return if the object doesn't exist in the cache::
|
|
|
|
>>> cache.get('my_key', 'has expired')
|
|
'has expired'
|
|
|
|
To add a key only if it doesn't already exist, use the ``add()`` method.
|
|
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.
|
|
|
|
If you want to get a key's value or set a value if the key isn't in the cache,
|
|
there is the ``get_or_set()`` method. It takes the same parameters as ``get()``
|
|
but the default is set as the new cache value for that key, rather than simply
|
|
returned::
|
|
|
|
>>> cache.get('my_new_key') # returns None
|
|
>>> cache.get_or_set('my_new_key', 'my new value', 100)
|
|
'my new value'
|
|
|
|
You can also pass any callable as a *default* value::
|
|
|
|
>>> import datetime
|
|
>>> cache.get_or_set('some-timestamp-key', datetime.datetime.now)
|
|
datetime.datetime(2014, 12, 11, 0, 15, 49, 457920)
|
|
|
|
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:
|
|
|
|
Cache key prefixing
|
|
-------------------
|
|
|
|
If you are sharing a cache instance between servers, or between your
|
|
production and development environments, it's possible for data cached
|
|
by one server to be used by another server. If the format of cached
|
|
data is different between servers, this can lead to some very hard to
|
|
diagnose problems.
|
|
|
|
To prevent this, Django provides the ability to prefix all cache keys
|
|
used by a server. When a particular cache key is saved or retrieved,
|
|
Django will automatically prefix the cache key with the value of the
|
|
:setting:`KEY_PREFIX <CACHES-KEY_PREFIX>` cache setting.
|
|
|
|
By ensuring each Django instance has a different
|
|
:setting:`KEY_PREFIX <CACHES-KEY_PREFIX>`, you can ensure that there will be no
|
|
collisions in cache values.
|
|
|
|
.. _cache_versioning:
|
|
|
|
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 :setting:`VERSION <CACHES-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:
|
|
|
|
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 :setting:`KEY_FUNCTION <CACHES-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
|
|
:setting:`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
|
|
:setting:`BACKEND <CACHES-BACKEND>` portion of your :setting:`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 website.
|
|
|
|
Here are a few examples of downstream caches:
|
|
|
|
* Your ISP may cache certain pages, so if you requested a page from
|
|
https://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 website 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:
|
|
|
|
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.,
|
|
``"https://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.
|
|
|
|
To do this in Django, use the convenient
|
|
:func:`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
|
|
:func:`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, :func:`django.utils.cache.patch_vary_headers`,
|
|
directly. This function sets, or adds to, the ``Vary header``. For example::
|
|
|
|
from django.shortcuts import render
|
|
from django.utils.cache import patch_vary_headers
|
|
|
|
def my_view(request):
|
|
...
|
|
response = render(request, 'template_name', context)
|
|
patch_vary_headers(response, ['Cookie'])
|
|
return response
|
|
|
|
``patch_vary_headers`` takes an :class:`~django.http.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 :rfc:`official Vary spec
|
|
<7231#section-7.1.4>`.
|
|
|
|
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 :func:`~django.views.decorators.cache.cache_control` view
|
|
decorator. Example::
|
|
|
|
from django.views.decorators.cache import cache_control
|
|
|
|
@cache_control(private=True)
|
|
def my_view(request):
|
|
...
|
|
|
|
This decorator takes care of sending out the appropriate HTTP header behind the
|
|
scenes.
|
|
|
|
Note that the cache control settings "private" and "public" are mutually
|
|
exclusive. The decorator ensures that the "public" directive is removed if
|
|
"private" should be set (and vice versa). 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
|
|
:func:`~django.utils.cache.patch_cache_control`, the manual way to modify the
|
|
cache control header (it is internally called by the
|
|
:func:`~django.views.decorators.cache.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
|
|
|
|
You can control downstream caches in other ways as well (see :rfc:`7234` for
|
|
details on HTTP caching). For example, even if you don't use Django's
|
|
server-side cache framework, you can still tell clients to cache a view for a
|
|
certain amount of time with the :rfc:`max-age <7234#section-5.2.2.8>`
|
|
directive::
|
|
|
|
from django.views.decorators.cache import cache_control
|
|
|
|
@cache_control(max_age=3600)
|
|
def my_view(request):
|
|
...
|
|
|
|
(If you *do* use the caching middleware, it already sets the ``max-age`` with
|
|
the value of the :setting:`CACHE_MIDDLEWARE_SECONDS` setting. In that case,
|
|
the custom ``max_age`` from the
|
|
:func:`~django.views.decorators.cache.cache_control` decorator will take
|
|
precedence, and the header values will be merged correctly.)
|
|
|
|
Any valid ``Cache-Control`` response directive is valid in ``cache_control()``.
|
|
Here are some more examples:
|
|
|
|
* ``no_transform=True``
|
|
* ``must_revalidate=True``
|
|
* ``stale_while_revalidate=num_seconds``
|
|
|
|
The full list of known directives can be found in the `IANA registry`_
|
|
(note that not all of them apply to responses).
|
|
|
|
.. _IANA registry: http://www.iana.org/assignments/http-cache-directives/http-cache-directives.xhtml
|
|
|
|
If you want to use headers to disable caching altogether,
|
|
:func:`~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``
|
|
=======================
|
|
|
|
If you use caching middleware, it's important to put each half in the right
|
|
place within the :setting:`MIDDLEWARE` setting. That's because the cache
|
|
middleware needs to know which headers by which to vary the cache storage.
|
|
Middleware always adds something to the ``Vary`` response header when it can.
|
|
|
|
``UpdateCacheMiddleware`` runs during the response phase, where middleware is
|
|
run in reverse order, so an item at the top of the list runs *last* during the
|
|
response phase. Thus, you need to make sure that ``UpdateCacheMiddleware``
|
|
appears *before* any other middleware that might add something to the ``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.
|