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:
Malcolm Tredinnick 2007-11-29 16:57:18 +00:00
parent 0171f00761
commit f2f6e70b08
3 changed files with 53 additions and 6 deletions

View File

@ -1,14 +1,18 @@
from django.conf import settings from django.conf import settings
from django.core.cache import cache 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): class CacheMiddleware(object):
""" """
Cache middleware. If this is enabled, each Django-powered page will be 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. 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 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 (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 simple and effective way of avoiding the caching of the Django admin (and
@ -78,7 +82,16 @@ class CacheMiddleware(object):
return response return response
if not response.status_code == 200: if not response.status_code == 200:
return response return response
patch_response_headers(response, self.cache_timeout) # Try to get the timeout from the "max-age" section of the "Cache-
cache_key = learn_cache_key(request, response, self.cache_timeout, self.key_prefix) # Control" header before reverting to using the default cache_timeout
cache.set(cache_key, response, self.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 return response

View File

@ -74,6 +74,21 @@ def patch_cache_control(response, **kwargs):
cc = ', '.join([dictvalue(el) for el in cc.items()]) cc = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc 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): def patch_response_headers(response, cache_timeout=None):
""" """
Adds some useful headers to the given HttpResponse object: 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 # for the request.path
cache.set(cache_key, [], cache_timeout) cache.set(cache_key, [], cache_timeout)
return _generate_cache_key(request, [], key_prefix) 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

View File

@ -263,6 +263,18 @@ See the `middleware documentation`_ for more on middleware.
.. _`middleware documentation`: ../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 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.) precedence, and the header values will be merged correctly.)
If you want to use headers to disable caching altogether, 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:: headers to ensure the response won't be cached by browsers or other caches. Example::
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache