Fixed #5813 -- Taught the CacheMiddleware to respect any max-age HTTP header
when setting the expiry time. Thanks, SmileyChris. git-svn-id: http://code.djangoproject.com/svn/django/trunk@6736 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0171f00761
commit
f2f6e70b08
|
@ -1,14 +1,18 @@
|
|||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers
|
||||
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
|
||||
|
||||
class CacheMiddleware(object):
|
||||
"""
|
||||
Cache middleware. If this is enabled, each Django-powered page will be
|
||||
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs.
|
||||
cached (based on URLs).
|
||||
|
||||
Only parameter-less GET or HEAD-requests with status code 200 are cached.
|
||||
|
||||
The number of seconds each page is stored for is set by the
|
||||
"max-age" section of the response's "Cache-Control" header, falling back to
|
||||
the CACHE_MIDDLEWARE_SECONDS setting if the section was not found.
|
||||
|
||||
If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests
|
||||
(i.e., those not made by a logged-in user) will be cached. This is a
|
||||
simple and effective way of avoiding the caching of the Django admin (and
|
||||
|
@ -78,7 +82,16 @@ class CacheMiddleware(object):
|
|||
return response
|
||||
if not response.status_code == 200:
|
||||
return response
|
||||
patch_response_headers(response, self.cache_timeout)
|
||||
cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix)
|
||||
cache.set(cache_key, response, self.cache_timeout)
|
||||
# Try to get the timeout from the "max-age" section of the "Cache-
|
||||
# Control" header before reverting to using the default cache_timeout
|
||||
# length.
|
||||
timeout = get_max_age(response)
|
||||
if timeout == None:
|
||||
timeout = self.cache_timeout
|
||||
elif timeout == 0:
|
||||
# max-age was set to 0, don't bother caching.
|
||||
return response
|
||||
patch_response_headers(response, timeout)
|
||||
cache_key = learn_cache_key(request, response, timeout, self.key_prefix)
|
||||
cache.set(cache_key, response, timeout)
|
||||
return response
|
||||
|
|
|
@ -74,6 +74,21 @@ def patch_cache_control(response, **kwargs):
|
|||
cc = ', '.join([dictvalue(el) for el in cc.items()])
|
||||
response['Cache-Control'] = cc
|
||||
|
||||
def get_max_age(response):
|
||||
"""
|
||||
Returns the max-age from the response Cache-Control header as an integer
|
||||
(or ``None`` if it wasn't found or wasn't an integer.
|
||||
"""
|
||||
if not response.has_header('Cache-Control'):
|
||||
return
|
||||
cc = dict([_to_tuple(el) for el in
|
||||
cc_delim_re.split(response['Cache-Control'])])
|
||||
if 'max-age' in cc:
|
||||
try:
|
||||
return int(cc['max-age'])
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
def patch_response_headers(response, cache_timeout=None):
|
||||
"""
|
||||
Adds some useful headers to the given HttpResponse object:
|
||||
|
@ -180,3 +195,10 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
|
|||
# for the request.path
|
||||
cache.set(cache_key, [], cache_timeout)
|
||||
return _generate_cache_key(request, [], key_prefix)
|
||||
|
||||
|
||||
def _to_tuple(s):
|
||||
t = s.split('=',1)
|
||||
if len(t) == 2:
|
||||
return t[0].lower(), t[1]
|
||||
return t[0].lower(), True
|
||||
|
|
|
@ -263,6 +263,18 @@ See the `middleware documentation`_ for more on middleware.
|
|||
|
||||
.. _`middleware documentation`: ../middleware/
|
||||
|
||||
**New in Django development version**
|
||||
|
||||
If a view sets its own cache expiry time (i.e. it has a ``max-age`` section in
|
||||
its ``Cache-Control`` header) then the page will be cached until the expiry
|
||||
time, rather than ``CACHE_MIDDLEWARE_SECONDS``. Using the decorators in
|
||||
``django.views.decorators.cache`` you can easily set a view's expiry time
|
||||
(using the ``cache_control`` decorator) or disable caching for a view (using
|
||||
the ``never_cache`` decorator). See the `using other headers`__ section for
|
||||
more on these decorators.
|
||||
|
||||
__ `Controlling cache: Using other headers`_
|
||||
|
||||
The per-view cache
|
||||
==================
|
||||
|
||||
|
@ -566,7 +578,7 @@ the value of the ``CACHE_MIDDLEWARE_SETTINGS`` setting. If you use a custom
|
|||
precedence, and the header values will be merged correctly.)
|
||||
|
||||
If you want to use headers to disable caching altogether,
|
||||
``django.views.decorators.never_cache`` is a view decorator that adds
|
||||
``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
|
||||
|
|
Loading…
Reference in New Issue