| 1 |
======================== |
|---|
| 2 |
Django's cache framework |
|---|
| 3 |
======================== |
|---|
| 4 |
|
|---|
| 5 |
A fundamental tradeoff in dynamic Web sites is, well, they're dynamic. Each |
|---|
| 6 |
time a user requests a page, the Web server makes all sorts of calculations -- |
|---|
| 7 |
from database queries to template rendering to business logic -- to create the |
|---|
| 8 |
page that your site's visitor sees. This is a lot more expensive, from a |
|---|
| 9 |
processing-overhead perspective, than your standard read-a-file-off-the-filesystem |
|---|
| 10 |
server arrangement. |
|---|
| 11 |
|
|---|
| 12 |
For most Web applications, this overhead isn't a big deal. Most Web |
|---|
| 13 |
applications aren't washingtonpost.com or slashdot.org; they're simply small- |
|---|
| 14 |
to medium-sized sites with so-so traffic. But for medium- to high-traffic |
|---|
| 15 |
sites, it's essential to cut as much overhead as possible. |
|---|
| 16 |
|
|---|
| 17 |
That's where caching comes in. |
|---|
| 18 |
|
|---|
| 19 |
To cache something is to save the result of an expensive calculation so that |
|---|
| 20 |
you don't have to perform the calculation next time. Here's some pseudocode |
|---|
| 21 |
explaining how this would work for a dynamically generated Web page:: |
|---|
| 22 |
|
|---|
| 23 |
given a URL, try finding that page in the cache |
|---|
| 24 |
if the page is in the cache: |
|---|
| 25 |
return the cached page |
|---|
| 26 |
else: |
|---|
| 27 |
generate the page |
|---|
| 28 |
save the generated page in the cache (for next time) |
|---|
| 29 |
return the generated page |
|---|
| 30 |
|
|---|
| 31 |
Django comes with a robust cache system that lets you save dynamic pages so |
|---|
| 32 |
they don't have to be calculated for each request. For convenience, Django |
|---|
| 33 |
offers different levels of cache granularity: You can cache the output of |
|---|
| 34 |
specific views, you can cache only the pieces that are difficult to produce, or |
|---|
| 35 |
you can cache your entire site. |
|---|
| 36 |
|
|---|
| 37 |
Django also works well with "upstream" caches, such as Squid |
|---|
| 38 |
(http://www.squid-cache.org/) and browser-based caches. These are the types of |
|---|
| 39 |
caches that you don't directly control but to which you can provide hints (via |
|---|
| 40 |
HTTP headers) about which parts of your site should be cached, and how. |
|---|
| 41 |
|
|---|
| 42 |
Setting up the cache |
|---|
| 43 |
==================== |
|---|
| 44 |
|
|---|
| 45 |
The cache system requires a small amount of setup. Namely, you have to tell it |
|---|
| 46 |
where your cached data should live -- whether in a database, on the filesystem |
|---|
| 47 |
or directly in memory. This is an important decision that affects your cache's |
|---|
| 48 |
performance; yes, some cache types are faster than others. |
|---|
| 49 |
|
|---|
| 50 |
Your cache preference goes in the ``CACHE_BACKEND`` setting in your settings |
|---|
| 51 |
file. Here's an explanation of all available values for CACHE_BACKEND. |
|---|
| 52 |
|
|---|
| 53 |
Memcached |
|---|
| 54 |
--------- |
|---|
| 55 |
|
|---|
| 56 |
By far the fastest, most efficient type of cache available to Django, Memcached |
|---|
| 57 |
is an entirely memory-based cache framework originally developed to handle high |
|---|
| 58 |
loads at LiveJournal.com and subsequently open-sourced by Danga Interactive. |
|---|
| 59 |
It's used by sites such as Slashdot and Wikipedia to reduce database access and |
|---|
| 60 |
dramatically increase site performance. |
|---|
| 61 |
|
|---|
| 62 |
Memcached is available for free at http://danga.com/memcached/ . It runs as a |
|---|
| 63 |
daemon and is allotted a specified amount of RAM. All it does is provide an |
|---|
| 64 |
interface -- a *super-lightning-fast* interface -- for adding, retrieving and |
|---|
| 65 |
deleting arbitrary data in the cache. All data is stored directly in memory, |
|---|
| 66 |
so there's no overhead of database or filesystem usage. |
|---|
| 67 |
|
|---|
| 68 |
After installing Memcached itself, you'll need to install the Memcached Python |
|---|
| 69 |
bindings. They're in a single Python module, memcache.py, available at |
|---|
| 70 |
ftp://ftp.tummy.com/pub/python-memcached/ . If that URL is no longer valid, |
|---|
| 71 |
just go to the Memcached Web site (http://www.danga.com/memcached/) and get the |
|---|
| 72 |
Python bindings from the "Client APIs" section. |
|---|
| 73 |
|
|---|
| 74 |
To use Memcached with Django, set ``CACHE_BACKEND`` to |
|---|
| 75 |
``memcached://ip:port/``, where ``ip`` is the IP address of the Memcached |
|---|
| 76 |
daemon and ``port`` is the port on which Memcached is running. |
|---|
| 77 |
|
|---|
| 78 |
In this example, Memcached is running on localhost (127.0.0.1) port 11211:: |
|---|
| 79 |
|
|---|
| 80 |
CACHE_BACKEND = 'memcached://127.0.0.1:11211/' |
|---|
| 81 |
|
|---|
| 82 |
One excellent feature of Memcached is its ability to share cache over multiple |
|---|
| 83 |
servers. To take advantage of this feature, include all server addresses in |
|---|
| 84 |
``CACHE_BACKEND``, separated by semicolons. In this example, the cache is |
|---|
| 85 |
shared over Memcached instances running on IP address 172.19.26.240 and |
|---|
| 86 |
172.19.26.242, both on port 11211:: |
|---|
| 87 |
|
|---|
| 88 |
CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11211/' |
|---|
| 89 |
|
|---|
| 90 |
Memory-based caching has one disadvantage: Because the cached data is stored in |
|---|
| 91 |
memory, the data will be lost if your server crashes. Clearly, memory isn't |
|---|
| 92 |
intended for permanent data storage, so don't rely on memory-based caching as |
|---|
| 93 |
your only data storage. Actually, none of the Django caching backends should be |
|---|
| 94 |
used for permanent storage -- they're all intended to be solutions for caching, |
|---|
| 95 |
not storage -- but we point this out here because memory-based caching is |
|---|
| 96 |
particularly temporary. |
|---|
| 97 |
|
|---|
| 98 |
Database caching |
|---|
| 99 |
---------------- |
|---|
| 100 |
|
|---|
| 101 |
To use a database table as your cache backend, first create a cache table in |
|---|
| 102 |
your database by running this command:: |
|---|
| 103 |
|
|---|
| 104 |
python manage.py createcachetable [cache_table_name] |
|---|
| 105 |
|
|---|
| 106 |
...where ``[cache_table_name]`` is the name of the database table to create. |
|---|
| 107 |
(This name can be whatever you want, as long as it's a valid table name that's |
|---|
| 108 |
not already being used in your database.) This command creates a single table |
|---|
| 109 |
in your database that is in the proper format that Django's database-cache |
|---|
| 110 |
system expects. |
|---|
| 111 |
|
|---|
| 112 |
Once you've created that database table, set your ``CACHE_BACKEND`` setting to |
|---|
| 113 |
``"db://tablename/"``, where ``tablename`` is the name of the database table. |
|---|
| 114 |
In this example, the cache table's name is ``my_cache_table``: |
|---|
| 115 |
|
|---|
| 116 |
CACHE_BACKEND = 'db://my_cache_table' |
|---|
| 117 |
|
|---|
| 118 |
Database caching works best if you've got a fast, well-indexed database server. |
|---|
| 119 |
|
|---|
| 120 |
Filesystem caching |
|---|
| 121 |
------------------ |
|---|
| 122 |
|
|---|
| 123 |
To store cached items on a filesystem, use the ``"file://"`` cache type for |
|---|
| 124 |
``CACHE_BACKEND``. For example, to store cached data in ``/var/tmp/django_cache``, |
|---|
| 125 |
use this setting:: |
|---|
| 126 |
|
|---|
| 127 |
CACHE_BACKEND = 'file:///var/tmp/django_cache' |
|---|
| 128 |
|
|---|
| 129 |
Note that there are three forward slashes toward the beginning of that example. |
|---|
| 130 |
The first two are for ``file://``, and the third is the first character of the |
|---|
| 131 |
directory path, ``/var/tmp/django_cache``. |
|---|
| 132 |
|
|---|
| 133 |
The directory path should be absolute -- that is, it should start at the root |
|---|
| 134 |
of your filesystem. It doesn't matter whether you put a slash at the end of the |
|---|
| 135 |
setting. |
|---|
| 136 |
|
|---|
| 137 |
Make sure the directory pointed-to by this setting exists and is readable and |
|---|
| 138 |
writable by the system user under which your Web server runs. Continuing the |
|---|
| 139 |
above example, if your server runs as the user ``apache``, make sure the |
|---|
| 140 |
directory ``/var/tmp/django_cache`` exists and is readable and writable by the |
|---|
| 141 |
user ``apache``. |
|---|
| 142 |
|
|---|
| 143 |
Local-memory caching |
|---|
| 144 |
-------------------- |
|---|
| 145 |
|
|---|
| 146 |
If you want the speed advantages of in-memory caching but don't have the |
|---|
| 147 |
capability of running Memcached, consider the local-memory cache backend. This |
|---|
| 148 |
cache is multi-process and thread-safe. To use it, set ``CACHE_BACKEND`` to |
|---|
| 149 |
``"locmem:///"``. For example:: |
|---|
| 150 |
|
|---|
| 151 |
CACHE_BACKEND = 'locmem:///' |
|---|
| 152 |
|
|---|
| 153 |
Simple caching (for development) |
|---|
| 154 |
-------------------------------- |
|---|
| 155 |
|
|---|
| 156 |
A simple, single-process memory cache is available as ``"simple:///"``. This |
|---|
| 157 |
merely saves cached data in-process, which means it should only be used in |
|---|
| 158 |
development or testing environments. For example:: |
|---|
| 159 |
|
|---|
| 160 |
CACHE_BACKEND = 'simple:///' |
|---|
| 161 |
|
|---|
| 162 |
Dummy caching (for development) |
|---|
| 163 |
------------------------------- |
|---|
| 164 |
|
|---|
| 165 |
Finally, Django comes with a "dummy" cache that doesn't actually cache -- it |
|---|
| 166 |
just implements the cache interface without doing anything. |
|---|
| 167 |
|
|---|
| 168 |
This is useful if you have a production site that uses heavy-duty caching in |
|---|
| 169 |
various places but a development/test environment on which you don't want to |
|---|
| 170 |
cache. In that case, set ``CACHE_BACKEND`` to ``"dummy:///"`` in the settings |
|---|
| 171 |
file for your development environment. As a result, your development |
|---|
| 172 |
environment won't use caching and your production environment still will. |
|---|
| 173 |
|
|---|
| 174 |
CACHE_BACKEND arguments |
|---|
| 175 |
----------------------- |
|---|
| 176 |
|
|---|
| 177 |
All caches may take arguments. They're given in query-string style on the |
|---|
| 178 |
``CACHE_BACKEND`` setting. Valid arguments are: |
|---|
| 179 |
|
|---|
| 180 |
timeout |
|---|
| 181 |
Default timeout, in seconds, to use for the cache. Defaults to 5 |
|---|
| 182 |
minutes (300 seconds). |
|---|
| 183 |
|
|---|
| 184 |
max_entries |
|---|
| 185 |
For the simple and database backends, the maximum number of entries |
|---|
| 186 |
allowed in the cache before it is cleaned. Defaults to 300. |
|---|
| 187 |
|
|---|
| 188 |
cull_percentage |
|---|
| 189 |
The percentage of entries that are culled when max_entries is reached. |
|---|
| 190 |
The actual percentage is 1/cull_percentage, so set cull_percentage=3 to |
|---|
| 191 |
cull 1/3 of the entries when max_entries is reached. |
|---|
| 192 |
|
|---|
| 193 |
A value of 0 for cull_percentage means that the entire cache will be |
|---|
| 194 |
dumped when max_entries is reached. This makes culling *much* faster |
|---|
| 195 |
at the expense of more cache misses. |
|---|
| 196 |
|
|---|
| 197 |
In this example, ``timeout`` is set to ``60``:: |
|---|
| 198 |
|
|---|
| 199 |
CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=60" |
|---|
| 200 |
|
|---|
| 201 |
In this example, ``timeout`` is ``30`` and ``max_entries`` is ``400``:: |
|---|
| 202 |
|
|---|
| 203 |
CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=30&max_entries=400" |
|---|
| 204 |
|
|---|
| 205 |
Invalid arguments are silently ignored, as are invalid values of known |
|---|
| 206 |
arguments. |
|---|
| 207 |
|
|---|
| 208 |
The per-site cache |
|---|
| 209 |
================== |
|---|
| 210 |
|
|---|
| 211 |
Once the cache is set up, the simplest way to use caching is to cache your |
|---|
| 212 |
entire site. Just add ``'django.middleware.cache.CacheMiddleware'`` to your |
|---|
| 213 |
``MIDDLEWARE_CLASSES`` setting, as in this example:: |
|---|
| 214 |
|
|---|
| 215 |
MIDDLEWARE_CLASSES = ( |
|---|
| 216 |
'django.middleware.cache.CacheMiddleware', |
|---|
| 217 |
'django.middleware.common.CommonMiddleware', |
|---|
| 218 |
) |
|---|
| 219 |
|
|---|
| 220 |
(The order of ``MIDDLEWARE_CLASSES`` matters. See "Order of MIDDLEWARE_CLASSES" |
|---|
| 221 |
below.) |
|---|
| 222 |
|
|---|
| 223 |
Then, add the following required settings to your Django settings file: |
|---|
| 224 |
|
|---|
| 225 |
* ``CACHE_MIDDLEWARE_SECONDS`` -- The number of seconds each page should be |
|---|
| 226 |
cached. |
|---|
| 227 |
* ``CACHE_MIDDLEWARE_KEY_PREFIX`` -- If the cache is shared across multiple |
|---|
| 228 |
sites using the same Django installation, set this to the name of the site, |
|---|
| 229 |
or some other string that is unique to this Django instance, to prevent key |
|---|
| 230 |
collisions. Use an empty string if you don't care. |
|---|
| 231 |
|
|---|
| 232 |
The cache middleware caches every page that doesn't have GET or POST |
|---|
| 233 |
parameters. Optionally, if the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting is |
|---|
| 234 |
``True``, only anonymous requests (i.e., not those made by a logged-in user) |
|---|
| 235 |
will be cached. This is a simple and effective way of disabling caching for any |
|---|
| 236 |
user-specific pages (include Django's admin interface). |
|---|
| 237 |
|
|---|
| 238 |
Additionally, ``CacheMiddleware`` automatically sets a few headers in each |
|---|
| 239 |
``HttpResponse``: |
|---|
| 240 |
|
|---|
| 241 |
* Sets the ``Last-Modified`` header to the current date/time when a fresh |
|---|
| 242 |
(uncached) version of the page is requested. |
|---|
| 243 |
* Sets the ``Expires`` header to the current date/time plus the defined |
|---|
| 244 |
``CACHE_MIDDLEWARE_SECONDS``. |
|---|
| 245 |
* Sets the ``Cache-Control`` header to give a max age for the page -- again, |
|---|
| 246 |
from the ``CACHE_MIDDLEWARE_SECONDS`` setting. |
|---|
| 247 |
|
|---|
| 248 |
See the `middleware documentation`_ for more on middleware. |
|---|
| 249 |
|
|---|
| 250 |
.. _`middleware documentation`: http://www.djangoproject.com/documentation/middleware/ |
|---|
| 251 |
|
|---|
| 252 |
The per-view cache |
|---|
| 253 |
================== |
|---|
| 254 |
|
|---|
| 255 |
A more granular way to use the caching framework is by caching the output of |
|---|
| 256 |
individual views. ``django.views.decorators.cache`` defines a ``cache_page`` |
|---|
| 257 |
decorator that will automatically cache the view's response for you. It's easy |
|---|
| 258 |
to use:: |
|---|
| 259 |
|
|---|
| 260 |
from django.views.decorators.cache import cache_page |
|---|
| 261 |
|
|---|
| 262 |
def slashdot_this(request): |
|---|
| 263 |
... |
|---|
| 264 |
|
|---|
| 265 |
slashdot_this = cache_page(slashdot_this, 60 * 15) |
|---|
| 266 |
|
|---|
| 267 |
Or, using Python 2.4's decorator syntax:: |
|---|
| 268 |
|
|---|
| 269 |
@cache_page(60 * 15) |
|---|
| 270 |
def slashdot_this(request): |
|---|
| 271 |
... |
|---|
| 272 |
|
|---|
| 273 |
``cache_page`` takes a single argument: the cache timeout, in seconds. In the |
|---|
| 274 |
above example, the result of the ``slashdot_this()`` view will be cached for 15 |
|---|
| 275 |
minutes. |
|---|
| 276 |
|
|---|
| 277 |
The low-level cache API |
|---|
| 278 |
======================= |
|---|
| 279 |
|
|---|
| 280 |
Sometimes, however, caching an entire rendered page doesn't gain you very much. |
|---|
| 281 |
For example, you may find it's only necessary to cache the result of an |
|---|
| 282 |
intensive database query. In cases like this, you can use the low-level cache |
|---|
| 283 |
API to store objects in the cache with any level of granularity you like. |
|---|
| 284 |
|
|---|
| 285 |
The cache API is simple. The cache module, ``django.core.cache``, exports a |
|---|
| 286 |
``cache`` object that's automatically created from the ``CACHE_BACKEND`` |
|---|
| 287 |
setting:: |
|---|
| 288 |
|
|---|
| 289 |
>>> from django.core.cache import cache |
|---|
| 290 |
|
|---|
| 291 |
The basic interface is ``set(key, value, timeout_seconds)`` and ``get(key)``:: |
|---|
| 292 |
|
|---|
| 293 |
>>> cache.set('my_key', 'hello, world!', 30) |
|---|
| 294 |
>>> cache.get('my_key') |
|---|
| 295 |
'hello, world!' |
|---|
| 296 |
|
|---|
| 297 |
The ``timeout_seconds`` argument is optional and defaults to the ``timeout`` |
|---|
| 298 |
argument in the ``CACHE_BACKEND`` setting (explained above). |
|---|
| 299 |
|
|---|
| 300 |
If the object doesn't exist in the cache, ``cache.get()`` returns ``None``:: |
|---|
| 301 |
|
|---|
| 302 |
>>> cache.get('some_other_key') |
|---|
| 303 |
None |
|---|
| 304 |
|
|---|
| 305 |
# Wait 30 seconds for 'my_key' to expire... |
|---|
| 306 |
|
|---|
| 307 |
>>> cache.get('my_key') |
|---|
| 308 |
None |
|---|
| 309 |
|
|---|
| 310 |
get() can take a ``default`` argument:: |
|---|
| 311 |
|
|---|
| 312 |
>>> cache.get('my_key', 'has expired') |
|---|
| 313 |
'has expired' |
|---|
| 314 |
|
|---|
| 315 |
There's also a get_many() interface that only hits the cache once. get_many() |
|---|
| 316 |
returns a dictionary with all the keys you asked for that actually exist in the |
|---|
| 317 |
cache (and haven't expired):: |
|---|
| 318 |
|
|---|
| 319 |
>>> cache.set('a', 1) |
|---|
| 320 |
>>> cache.set('b', 2) |
|---|
| 321 |
>>> cache.set('c', 3) |
|---|
| 322 |
>>> cache.get_many(['a', 'b', 'c']) |
|---|
| 323 |
{'a': 1, 'b': 2, 'c': 3} |
|---|
| 324 |
|
|---|
| 325 |
Finally, you can delete keys explicitly with ``delete()``. This is an easy way |
|---|
| 326 |
of clearing the cache for a particular object:: |
|---|
| 327 |
|
|---|
| 328 |
>>> cache.delete('a') |
|---|
| 329 |
|
|---|
| 330 |
That's it. The cache has very few restrictions: You can cache any object that |
|---|
| 331 |
can be pickled safely, although keys must be strings. |
|---|
| 332 |
|
|---|
| 333 |
Upstream caches |
|---|
| 334 |
=============== |
|---|
| 335 |
|
|---|
| 336 |
So far, this document has focused on caching your *own* data. But another type |
|---|
| 337 |
of caching is relevant to Web development, too: caching performed by "upstream" |
|---|
| 338 |
caches. These are systems that cache pages for users even before the request |
|---|
| 339 |
reaches your Web site. |
|---|
| 340 |
|
|---|
| 341 |
Here are a few examples of upstream caches: |
|---|
| 342 |
|
|---|
| 343 |
* Your ISP may cache certain pages, so if you requested a page from |
|---|
| 344 |
somedomain.com, your ISP would send you the page without having to access |
|---|
| 345 |
somedomain.com directly. |
|---|
| 346 |
|
|---|
| 347 |
* Your Django Web site may sit behind a Squid Web proxy |
|---|
| 348 |
(http://www.squid-cache.org/) that caches pages for performance. In this |
|---|
| 349 |
case, each request first would be handled by Squid, and it'd only be |
|---|
| 350 |
passed to your application if needed. |
|---|
| 351 |
|
|---|
| 352 |
* Your Web browser caches pages, too. If a Web page sends out the right |
|---|
| 353 |
headers, your browser will use the local (cached) copy for subsequent |
|---|
| 354 |
requests to that page. |
|---|
| 355 |
|
|---|
| 356 |
Upstream caching is a nice efficiency boost, but there's a danger to it: |
|---|
| 357 |
Many Web pages' contents differ based on authentication and a host of other |
|---|
| 358 |
variables, and cache systems that blindly save pages based purely on URLs could |
|---|
| 359 |
expose incorrect or sensitive data to subsequent visitors to those pages. |
|---|
| 360 |
|
|---|
| 361 |
For example, say you operate a Web e-mail system, and the contents of the |
|---|
| 362 |
"inbox" page obviously depend on which user is logged in. If an ISP blindly |
|---|
| 363 |
cached your site, then the first user who logged in through that ISP would have |
|---|
| 364 |
his user-specific inbox page cached for subsequent visitors to the site. That's |
|---|
| 365 |
not cool. |
|---|
| 366 |
|
|---|
| 367 |
Fortunately, HTTP provides a solution to this problem: A set of HTTP headers |
|---|
| 368 |
exist to instruct caching mechanisms to differ their cache contents depending |
|---|
| 369 |
on designated variables, and to tell caching mechanisms not to cache particular |
|---|
| 370 |
pages. |
|---|
| 371 |
|
|---|
| 372 |
Using Vary headers |
|---|
| 373 |
================== |
|---|
| 374 |
|
|---|
| 375 |
One of these headers is ``Vary``. It defines which request headers a cache |
|---|
| 376 |
mechanism should take into account when building its cache key. For example, if |
|---|
| 377 |
the contents of a Web page depend on a user's language preference, the page is |
|---|
| 378 |
said to "vary on language." |
|---|
| 379 |
|
|---|
| 380 |
By default, Django's cache system creates its cache keys using the requested |
|---|
| 381 |
path -- e.g., ``"/stories/2005/jun/23/bank_robbed/"``. This means every request |
|---|
| 382 |
to that URL will use the same cached version, regardless of user-agent |
|---|
| 383 |
differences such as cookies or language preferences. |
|---|
| 384 |
|
|---|
| 385 |
That's where ``Vary`` comes in. |
|---|
| 386 |
|
|---|
| 387 |
If your Django-powered page outputs different content based on some difference |
|---|
| 388 |
in request headers -- such as a cookie, or language, or user-agent -- you'll |
|---|
| 389 |
need to use the ``Vary`` header to tell caching mechanisms that the page output |
|---|
| 390 |
depends on those things. |
|---|
| 391 |
|
|---|
| 392 |
To do this in Django, use the convenient ``vary_on_headers`` view decorator, |
|---|
| 393 |
like so:: |
|---|
| 394 |
|
|---|
| 395 |
from django.views.decorators.vary import vary_on_headers |
|---|
| 396 |
|
|---|
| 397 |
# Python 2.3 syntax. |
|---|
| 398 |
def my_view(request): |
|---|
| 399 |
... |
|---|
| 400 |
my_view = vary_on_headers(my_view, 'User-Agent') |
|---|
| 401 |
|
|---|
| 402 |
# Python 2.4 decorator syntax. |
|---|
| 403 |
@vary_on_headers('User-Agent') |
|---|
| 404 |
def my_view(request): |
|---|
| 405 |
... |
|---|
| 406 |
|
|---|
| 407 |
In this case, a caching mechanism (such as Django's own cache middleware) will |
|---|
| 408 |
cache a separate version of the page for each unique user-agent. |
|---|
| 409 |
|
|---|
| 410 |
The advantage to using the ``vary_on_headers`` decorator rather than manually |
|---|
| 411 |
setting the ``Vary`` header (using something like |
|---|
| 412 |
``response['Vary'] = 'user-agent'``) is that the decorator adds to the ``Vary`` |
|---|
| 413 |
header (which may already exist) rather than setting it from scratch. |
|---|
| 414 |
|
|---|
| 415 |
You can pass multiple headers to ``vary_on_headers()``:: |
|---|
| 416 |
|
|---|
| 417 |
@vary_on_headers('User-Agent', 'Cookie') |
|---|
| 418 |
def my_view(request): |
|---|
| 419 |
... |
|---|
| 420 |
|
|---|
| 421 |
Because varying on cookie is such a common case, there's a ``vary_on_cookie`` |
|---|
| 422 |
decorator. These two views are equivalent:: |
|---|
| 423 |
|
|---|
| 424 |
@vary_on_cookie |
|---|
| 425 |
def my_view(request): |
|---|
| 426 |
... |
|---|
| 427 |
|
|---|
| 428 |
@vary_on_headers('Cookie') |
|---|
| 429 |
def my_view(request): |
|---|
| 430 |
... |
|---|
| 431 |
|
|---|
| 432 |
Also note that the headers you pass to ``vary_on_headers`` are not case |
|---|
| 433 |
sensitive. ``"User-Agent"`` is the same thing as ``"user-agent"``. |
|---|
| 434 |
|
|---|
| 435 |
You can also use a helper function, ``django.utils.cache.patch_vary_headers``, |
|---|
| 436 |
directly:: |
|---|
| 437 |
|
|---|
| 438 |
from django.utils.cache import patch_vary_headers |
|---|
| 439 |
def my_view(request): |
|---|
| 440 |
... |
|---|
| 441 |
response = render_to_response('template_name', context) |
|---|
| 442 |
patch_vary_headers(response, ['Cookie']) |
|---|
| 443 |
return response |
|---|
| 444 |
|
|---|
| 445 |
``patch_vary_headers`` takes an ``HttpResponse`` instance as its first argument |
|---|
| 446 |
and a list/tuple of header names as its second argument. |
|---|
| 447 |
|
|---|
| 448 |
For more on Vary headers, see the `official Vary spec`_. |
|---|
| 449 |
|
|---|
| 450 |
.. _`official Vary spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 |
|---|
| 451 |
|
|---|
| 452 |
Controlling cache: Using other headers |
|---|
| 453 |
====================================== |
|---|
| 454 |
|
|---|
| 455 |
Another problem with caching is the privacy of data and the question of where |
|---|
| 456 |
data should be stored in a cascade of caches. |
|---|
| 457 |
|
|---|
| 458 |
A user usually faces two kinds of caches: his own browser cache (a private |
|---|
| 459 |
cache) and his provider's cache (a public cache). A public cache is used by |
|---|
| 460 |
multiple users and controlled by someone else. This poses problems with |
|---|
| 461 |
sensitive data: You don't want, say, your banking-account number stored in a |
|---|
| 462 |
public cache. So Web applications need a way to tell caches which data is |
|---|
| 463 |
private and which is public. |
|---|
| 464 |
|
|---|
| 465 |
The solution is to indicate a page's cache should be "private." To do this in |
|---|
| 466 |
Django, use the ``cache_control`` view decorator. Example:: |
|---|
| 467 |
|
|---|
| 468 |
from django.views.decorators.cache import cache_control |
|---|
| 469 |
@cache_control(private=True) |
|---|
| 470 |
def my_view(request): |
|---|
| 471 |
... |
|---|
| 472 |
|
|---|
| 473 |
This decorator takes care of sending out the appropriate HTTP header behind the |
|---|
| 474 |
scenes. |
|---|
| 475 |
|
|---|
| 476 |
There are a few other ways to control cache parameters. For example, HTTP |
|---|
| 477 |
allows applications to do the following: |
|---|
| 478 |
|
|---|
| 479 |
* Define the maximum time a page should be cached. |
|---|
| 480 |
* Specify whether a cache should always check for newer versions, only |
|---|
| 481 |
delivering the cached content when there are no changes. (Some caches |
|---|
| 482 |
might deliver cached content even if the server page changed -- simply |
|---|
| 483 |
because the cache copy isn't yet expired.) |
|---|
| 484 |
|
|---|
| 485 |
In Django, use the ``cache_control`` view decorator to specify these cache |
|---|
| 486 |
parameters. In this example, ``cache_control`` tells caches to revalidate the |
|---|
| 487 |
cache on every access and to store cached versions for, at most, 3600 seconds:: |
|---|
| 488 |
|
|---|
| 489 |
from django.views.decorators.cache import cache_control |
|---|
| 490 |
@cache_control(must_revalidate=True, max_age=3600) |
|---|
| 491 |
def my_view(request): |
|---|
| 492 |
... |
|---|
| 493 |
|
|---|
| 494 |
Any valid ``Cache-Control`` HTTP directive is valid in ``cache_control()``. |
|---|
| 495 |
Here's a full list: |
|---|
| 496 |
|
|---|
| 497 |
* ``public=True`` |
|---|
| 498 |
* ``private=True`` |
|---|
| 499 |
* ``no_cache=True`` |
|---|
| 500 |
* ``no_transform=True`` |
|---|
| 501 |
* ``must_revalidate=True`` |
|---|
| 502 |
* ``proxy_revalidate=True`` |
|---|
| 503 |
* ``max_age=num_seconds`` |
|---|
| 504 |
* ``s_maxage=num_seconds`` |
|---|
| 505 |
|
|---|
| 506 |
For explanation of Cache-Control HTTP directives, see the `Cache-Control spec`_. |
|---|
| 507 |
|
|---|
| 508 |
(Note that the caching middleware already sets the cache header's max-age with |
|---|
| 509 |
the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom |
|---|
| 510 |
``max_age`` in a ``cache_control`` decorator, the decorator will take |
|---|
| 511 |
precedence, and the header values will be merged correctly.) |
|---|
| 512 |
|
|---|
| 513 |
.. _`Cache-Control spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 |
|---|
| 514 |
|
|---|
| 515 |
Other optimizations |
|---|
| 516 |
=================== |
|---|
| 517 |
|
|---|
| 518 |
Django comes with a few other pieces of middleware that can help optimize your |
|---|
| 519 |
apps' performance: |
|---|
| 520 |
|
|---|
| 521 |
* ``django.middleware.http.ConditionalGetMiddleware`` adds support for |
|---|
| 522 |
conditional GET. This makes use of ``ETag`` and ``Last-Modified`` |
|---|
| 523 |
headers. |
|---|
| 524 |
|
|---|
| 525 |
* ``django.middleware.gzip.GZipMiddleware`` compresses content for browsers |
|---|
| 526 |
that understand gzip compression (all modern browsers). |
|---|
| 527 |
|
|---|
| 528 |
Order of MIDDLEWARE_CLASSES |
|---|
| 529 |
=========================== |
|---|
| 530 |
|
|---|
| 531 |
If you use ``CacheMiddleware``, it's important to put it in the right place |
|---|
| 532 |
within the ``MIDDLEWARE_CLASSES`` setting, because the cache middleware needs |
|---|
| 533 |
to know which headers by which to vary the cache storage. Middleware always |
|---|
| 534 |
adds something the ``Vary`` response header when it can. |
|---|
| 535 |
|
|---|
| 536 |
Put the ``CacheMiddleware`` after any middlewares that might add something to |
|---|
| 537 |
the ``Vary`` header. The following middlewares do so: |
|---|
| 538 |
|
|---|
| 539 |
* ``SessionMiddleware`` adds ``Cookie`` |
|---|
| 540 |
* ``GZipMiddleware`` adds ``Accept-Encoding`` |
|---|