Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7526590

Browse files
committed
Split CacheMiddleware up into two parts -- an update-cache and a fetch-from-cache middleware. This lets you run each half of the cache middleware at the correct time to avoid bad interactions between the cache middleware and other middleware that must modify the cache key (like the locale middleware).
CacheMiddleware itself is still around for backwards-compatibility and as a hook point for the cache decorator, but the documentation has been updated to point people towards the two-part caching middleware. Refs #730. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8260 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent e8f1864 commit 7526590

File tree

2 files changed

+144
-71
lines changed

2 files changed

+144
-71
lines changed

‎django/middleware/cache.py‎

Lines changed: 115 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,72 @@
1-
from django.conf import settings
2-
from django.core.cache import cache
3-
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
1+
"""
2+
Cache middleware. If enabled, each Django-powered page will be cached based on
3+
URL. The cannonical way to enable cache middleware is to set
4+
``UpdateCacheMiddleware`` as your first piece of middleware, and
5+
``FetchFromCacheMiddleware`` as the last::
46
5-
class CacheMiddleware(object):
6-
"""
7-
Cache middleware. If this is enabled, each Django-powered page will be
8-
cached (based on URLs).
7+
MIDDLEWARE_CLASSES = [
8+
'django.middleware.cache.UpdateCacheMiddleware',
9+
...
10+
'django.middleware.cache.FetchFromCacheMiddleware'
11+
]
912
10-
Only parameter-less GET or HEAD-requests with status code 200 are cached.
13+
This is counter-intuitive, but correct: ``UpdateCacheMiddleware`` needs to run
14+
last during the response phase, which processes middleware bottom-up;
15+
``FetchFromCacheMiddleware`` needs to run last during the request phase, which
16+
processes middleware top-down.
1117
12-
The number of seconds each page is stored for is set by the
13-
"max-age" section of the response's "Cache-Control" header, falling back to
14-
the CACHE_MIDDLEWARE_SECONDS setting if the section was not found.
18+
The single-class ``CacheMiddleware`` can be used for some simple sites. However,
19+
if any other peice of middleware needs to affect the cache key, you'll need to
20+
use the two-part UpdateCacheMiddleware and FetchFromCacheMiddleware. This'll
21+
most often happen when you're using Django's LocaleMiddleware.
1522
16-
If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
17-
(i.e., those not made by a logged-in user) will be cached. This is a
18-
simple and effective way of avoiding the caching of the Django admin (and
19-
any other user-specific content).
23+
More details about how the caching works:
2024
21-
This middleware expects that a HEAD request is answered with a response
22-
exactly like the corresponding GET request.
25+
* Only parameter-less GET or HEAD-requests with status code 200 are cached.
2326
24-
When a hit occurs, a shallow copy of the original response object is
25-
returned from process_request.
27+
* The number of seconds each page is stored for is set by the "max-age" section
28+
of the response's "Cache-Control" header, falling back to the
29+
CACHE_MIDDLEWARE_SECONDS setting if the section was not found.
2630
27-
Pages will be cached based on the contents of the request headers
28-
listed in the response's "Vary" header. This means that pages shouldn't
29-
change their "Vary" header.
31+
* If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
32+
(i.e., those not made by a logged-in user) will be cached. This is a simple
33+
and effective way of avoiding the caching of the Django admin (and any other
34+
user-specific content).
3035
31-
This middleware also sets ETag, Last-Modified, Expires and Cache-Control
32-
headers on the response object.
33-
"""
34-
def __init__(self, cache_timeout=None, key_prefix=None, cache_anonymous_only=None):
35-
self.cache_timeout = cache_timeout
36-
if cache_timeout is None:
37-
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
38-
self.key_prefix = key_prefix
39-
if key_prefix is None:
40-
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
41-
if cache_anonymous_only is None:
42-
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
43-
else:
44-
self.cache_anonymous_only = cache_anonymous_only
36+
* This middleware expects that a HEAD request is answered with a response
37+
exactly like the corresponding GET request.
4538
46-
def process_request(self, request):
47-
"Checks whether the page is already cached and returns the cached version if available."
48-
if self.cache_anonymous_only:
49-
assert hasattr(request, 'user'), "The Django cache middleware with CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True requires authentication middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware' before the CacheMiddleware."
39+
* When a hit occurs, a shallow copy of the original response object is returned
40+
from process_request.
5041
51-
if not request.method in ('GET', 'HEAD') or request.GET:
52-
request._cache_update_cache = False
53-
return None # Don't bother checking the cache.
42+
* Pages will be cached based on the contents of the request headers listed in
43+
the response's "Vary" header.
5444
55-
if self.cache_anonymous_only and request.user.is_authenticated():
56-
request._cache_update_cache = False
57-
return None # Don't cache requests from authenticated users.
45+
* This middleware also sets ETag, Last-Modified, Expires and Cache-Control
46+
headers on the response object.
5847
59-
cache_key = get_cache_key(request, self.key_prefix)
60-
if cache_key is None:
61-
request._cache_update_cache = True
62-
return None # No cache information available, need to rebuild.
48+
"""
6349

64-
response = cache.get(cache_key, None)
65-
if response is None:
66-
request._cache_update_cache = True
67-
return None # No cache information available, need to rebuild.
50+
from django.conf import settings
51+
from django.core.cache import cache
52+
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
6853

69-
request._cache_update_cache = False
70-
return response
54+
class UpdateCacheMiddleware(object):
55+
"""
56+
Response-phase cache middleware that updates the cache if the response is
57+
cacheable.
58+
59+
Must be used as part of the two-part update/fetch cache middleware.
60+
UpdateCacheMiddleware must be the first piece of middleware in
61+
MIDDLEWARE_CLASSES so that it'll get called last during the response phase.
62+
"""
63+
def __init__(self):
64+
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
65+
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
66+
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
7167

7268
def process_response(self, request, response):
73-
"Sets the cache, if needed."
69+
"""Sets the cache, if needed."""
7470
if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache:
7571
# We don't need to update the cache, just return.
7672
return response
@@ -95,3 +91,65 @@ def process_response(self, request, response):
9591
cache_key = learn_cache_key(request, response, timeout, self.key_prefix)
9692
cache.set(cache_key, response, timeout)
9793
return response
94+
95+
class FetchFromCacheMiddleware(object):
96+
"""
97+
Request-phase cache middleware that fetches a page from the cache.
98+
99+
Must be used as part of the two-part update/fetch cache middleware.
100+
FetchFromCacheMiddleware must be the last piece of middleware in
101+
MIDDLEWARE_CLASSES so that it'll get called last during the request phase.
102+
"""
103+
def __init__(self):
104+
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
105+
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
106+
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
107+
108+
def process_request(self, request):
109+
"""
110+
Checks whether the page is already cached and returns the cached
111+
version if available.
112+
"""
113+
if self.cache_anonymous_only:
114+
assert hasattr(request, 'user'), "The Django cache middleware with CACHE_MIDDLEWARE_ANONYMOUS_ONLY=True requires authentication middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.auth.middleware.AuthenticationMiddleware' before the CacheMiddleware."
115+
116+
if not request.method in ('GET', 'HEAD') or request.GET:
117+
request._cache_update_cache = False
118+
return None # Don't bother checking the cache.
119+
120+
if self.cache_anonymous_only and request.user.is_authenticated():
121+
request._cache_update_cache = False
122+
return None # Don't cache requests from authenticated users.
123+
124+
cache_key = get_cache_key(request, self.key_prefix)
125+
if cache_key is None:
126+
request._cache_update_cache = True
127+
return None # No cache information available, need to rebuild.
128+
129+
response = cache.get(cache_key, None)
130+
if response is None:
131+
request._cache_update_cache = True
132+
return None # No cache information available, need to rebuild.
133+
134+
request._cache_update_cache = False
135+
return response
136+
137+
class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
138+
"""
139+
Cache middleware that provides basic behavior for many simple sites.
140+
141+
Also used as the hook point for the cache decorator, which is generated
142+
using the decorator-from-middleware utility.
143+
"""
144+
def __init__(self, cache_timeout=None, key_prefix=None, cache_anonymous_only=None):
145+
self.cache_timeout = cache_timeout
146+
if cache_timeout is None:
147+
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
148+
self.key_prefix = key_prefix
149+
if key_prefix is None:
150+
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
151+
if cache_anonymous_only is None:
152+
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
153+
else:
154+
self.cache_anonymous_only = cache_anonymous_only
155+

‎docs/cache.txt‎

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,25 @@ arguments.
231231
The per-site cache
232232
==================
233233

234+
**New in Django development version** (previous versions of Django only provided a single ``CacheMiddleware`` instead of the two pieces described below).
235+
234236
Once the cache is set up, the simplest way to use caching is to cache your
235-
entire site. Just add ``'django.middleware.cache.CacheMiddleware'`` to your
237+
entire site. You'll need to add
238+
``'django.middleware.cache.UpdateCacheMiddleware'`` and
239+
``'django.middleware.cache.FetchFromCacheMiddleware' to your
236240
``MIDDLEWARE_CLASSES`` setting, as in this example::
237241

238242
MIDDLEWARE_CLASSES = (
239-
'django.middleware.cache.CacheMiddleware',
243+
'django.middleware.cache.UpdateCacheMiddleware',
240244
'django.middleware.common.CommonMiddleware',
245+
'django.middleware.cache.FetchFromCacheMiddleware',
241246
)
242247

243-
(The order of ``MIDDLEWARE_CLASSES`` matters. See `Order of MIDDLEWARE_CLASSES`_
244-
below.)
248+
.. note::
249+
250+
No, that's not a typo: the "update" middleware must be first in the list,
251+
and the "fetch" middleware must be last. The details are a bit obscure, but
252+
see `Order of MIDDLEWARE_CLASSES`_ below if you'd like the full story.
245253

246254
Then, add the following required settings to your Django settings file:
247255

@@ -258,10 +266,9 @@ parameters. Optionally, if the ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting is
258266
will be cached. This is a simple and effective way of disabling caching for any
259267
user-specific pages (include Django's admin interface). Note that if you use
260268
``CACHE_MIDDLEWARE_ANONYMOUS_ONLY``, you should make sure you've activated
261-
``AuthenticationMiddleware`` and that ``AuthenticationMiddleware`` appears
262-
before ``CacheMiddleware`` in your ``MIDDLEWARE_CLASSES``.
269+
``AuthenticationMiddleware``.
263270

264-
Additionally, ``CacheMiddleware`` automatically sets a few headers in each
271+
Additionally, the cache middleware automatically sets a few headers in each
265272
``HttpResponse``:
266273

267274
* Sets the ``Last-Modified`` header to the current date/time when a fresh
@@ -627,16 +634,24 @@ apps' performance:
627634
Order of MIDDLEWARE_CLASSES
628635
===========================
629636

630-
If you use ``CacheMiddleware``, it's important to put it in the right place
631-
within the ``MIDDLEWARE_CLASSES`` setting, because the cache middleware needs
632-
to know which headers by which to vary the cache storage. Middleware always
633-
adds something to the ``Vary`` response header when it can.
637+
If you use caching middlewaare, it's important to put each half in the right
638+
place within the ``MIDDLEWARE_CLASSES`` setting. That's because the cache
639+
middleware needs to know which headers by which to vary the cache storage.
640+
Middleware always adds something to the ``Vary`` response header when it can.
634641

635-
Put the ``CacheMiddleware`` *before* any other middleware that might add
636-
something to the ``Vary`` header (response middleware is applied in reverse
637-
order). The following middleware modules do so:
642+
``UpdateCacheMiddleware`` runs during the response phase, where middleware is
643+
run in reverse order, so an item at the top of the list runs *last* during the
644+
response phase. Thus, you need to make sure that ``UpdateCacheMiddleware``
645+
appears *before* any other middleware that might add something to the ``Vary``
646+
header. The following middleware modules do so:
638647

639648
* ``SessionMiddleware`` adds ``Cookie``
640649
* ``GZipMiddleware`` adds ``Accept-Encoding``
641650
* ``LocaleMiddleware`` adds ``Accept-Language``
651+
652+
``FetchFromCacheMiddleware``, on the other hand, runs during the request phase,
653+
where middleware is applied first-to-last, so an item at the top of the list
654+
runs *first* during the request phase. The ``FetchFromCacheMiddleware`` also
655+
needs to run after other middleware updates the ``Vary`` header, so
656+
``FetchFromCacheMiddleware`` must be *after* any item that does so.
642657

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /