2008-08-09 23:07:45 +08:00
"""
Cache middleware . If enabled , each Django - powered page will be cached based on
2008-08-16 01:47:03 +08:00
URL . The canonical way to enable cache middleware is to set
2008-08-09 23:07:45 +08:00
` ` UpdateCacheMiddleware ` ` as your first piece of middleware , and
` ` FetchFromCacheMiddleware ` ` as the last : :
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
MIDDLEWARE_CLASSES = [
' django.middleware.cache.UpdateCacheMiddleware ' ,
. . .
' django.middleware.cache.FetchFromCacheMiddleware '
]
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
This is counter - intuitive , but correct : ` ` UpdateCacheMiddleware ` ` needs to run
last during the response phase , which processes middleware bottom - up ;
` ` FetchFromCacheMiddleware ` ` needs to run last during the request phase , which
processes middleware top - down .
2005-07-19 03:07:37 +08:00
2008-08-16 01:47:03 +08:00
The single - class ` ` CacheMiddleware ` ` can be used for some simple sites .
However , if any other piece of middleware needs to affect the cache key , you ' ll
need to use the two - part ` ` UpdateCacheMiddleware ` ` and
` ` FetchFromCacheMiddleware ` ` . This ' ll most often happen when you ' re using
Django ' s ``LocaleMiddleware``.
2007-11-30 00:57:18 +08:00
2008-08-09 23:07:45 +08:00
More details about how the caching works :
2006-07-20 23:37:12 +08:00
2008-08-09 23:07:45 +08:00
* Only parameter - less GET or HEAD - requests with status code 200 are cached .
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
* 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 .
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
* 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 any other
user - specific content ) .
2005-10-09 08:55:08 +08:00
2010-10-29 09:31:15 +08:00
* This middleware expects that a HEAD request is answered with the same response
headers exactly like the corresponding GET request .
2005-10-09 08:55:08 +08:00
2008-08-09 23:07:45 +08:00
* When a hit occurs , a shallow copy of the original response object is returned
from process_request .
2006-08-18 11:31:13 +08:00
2008-08-09 23:07:45 +08:00
* Pages will be cached based on the contents of the request headers listed in
the response ' s " Vary " header.
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
* This middleware also sets ETag , Last - Modified , Expires and Cache - Control
headers on the response object .
2006-07-20 23:37:12 +08:00
2008-08-09 23:07:45 +08:00
"""
2005-07-19 03:07:37 +08:00
2008-08-09 23:07:45 +08:00
from django . conf import settings
2010-12-21 23:19:19 +08:00
from django . core . cache import get_cache , DEFAULT_CACHE_ALIAS
2008-08-09 23:07:45 +08:00
from django . utils . cache import get_cache_key , learn_cache_key , patch_response_headers , get_max_age
2005-10-09 08:55:08 +08:00
2008-08-09 23:07:45 +08:00
class UpdateCacheMiddleware ( object ) :
"""
Response - phase cache middleware that updates the cache if the response is
cacheable .
2008-08-16 01:47:03 +08:00
2008-08-09 23:07:45 +08:00
Must be used as part of the two - part update / fetch cache middleware .
UpdateCacheMiddleware must be the first piece of middleware in
MIDDLEWARE_CLASSES so that it ' ll get called last during the response phase.
"""
def __init__ ( self ) :
self . cache_timeout = settings . CACHE_MIDDLEWARE_SECONDS
self . key_prefix = settings . CACHE_MIDDLEWARE_KEY_PREFIX
self . cache_anonymous_only = getattr ( settings , ' CACHE_MIDDLEWARE_ANONYMOUS_ONLY ' , False )
2010-12-21 23:19:19 +08:00
self . cache = get_cache ( settings . CACHE_MIDDLEWARE_ALIAS )
2005-07-19 03:07:37 +08:00
def process_response ( self , request , response ) :
2008-08-09 23:07:45 +08:00
""" Sets the cache, if needed. """
2005-10-19 21:44:55 +08:00
if not hasattr ( request , ' _cache_update_cache ' ) or not request . _cache_update_cache :
2005-10-09 08:55:08 +08:00
# We don't need to update the cache, just return.
return response
if not response . status_code == 200 :
return response
2007-11-30 00:57:18 +08:00
# 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 )
2008-09-30 11:58:09 +08:00
if timeout :
2010-12-22 15:52:44 +08:00
cache_key = learn_cache_key ( request , response , timeout , self . key_prefix , cache = self . cache )
2010-12-21 23:19:19 +08:00
self . cache . set ( cache_key , response , timeout )
2005-07-19 03:07:37 +08:00
return response
2008-08-09 23:07:45 +08:00
class FetchFromCacheMiddleware ( object ) :
"""
Request - phase cache middleware that fetches a page from the cache .
2008-08-16 01:47:03 +08:00
2008-08-09 23:07:45 +08:00
Must be used as part of the two - part update / fetch cache middleware .
FetchFromCacheMiddleware must be the last piece of middleware in
MIDDLEWARE_CLASSES so that it ' ll get called last during the request phase.
"""
def __init__ ( self ) :
self . cache_timeout = settings . CACHE_MIDDLEWARE_SECONDS
self . key_prefix = settings . CACHE_MIDDLEWARE_KEY_PREFIX
self . cache_anonymous_only = getattr ( settings , ' CACHE_MIDDLEWARE_ANONYMOUS_ONLY ' , False )
2010-12-21 23:19:19 +08:00
self . cache = get_cache ( settings . CACHE_MIDDLEWARE_ALIAS )
2008-08-16 01:47:03 +08:00
2008-08-09 23:07:45 +08:00
def process_request ( self , request ) :
"""
Checks whether the page is already cached and returns the cached
version if available .
"""
if self . cache_anonymous_only :
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. "
if not request . method in ( ' GET ' , ' HEAD ' ) or request . GET :
request . _cache_update_cache = False
return None # Don't bother checking the cache.
if self . cache_anonymous_only and request . user . is_authenticated ( ) :
request . _cache_update_cache = False
return None # Don't cache requests from authenticated users.
2010-10-29 09:31:15 +08:00
# try and get the cached GET response
2010-12-22 15:52:44 +08:00
cache_key = get_cache_key ( request , self . key_prefix , ' GET ' , cache = self . cache )
2008-08-09 23:07:45 +08:00
if cache_key is None :
request . _cache_update_cache = True
return None # No cache information available, need to rebuild.
2010-12-21 23:19:19 +08:00
response = self . cache . get ( cache_key , None )
2010-10-29 09:31:15 +08:00
# if it wasn't found and we are looking for a HEAD, try looking just for that
if response is None and request . method == ' HEAD ' :
2010-12-22 15:52:44 +08:00
cache_key = get_cache_key ( request , self . key_prefix , ' HEAD ' , cache = self . cache )
2010-12-21 23:19:19 +08:00
response = self . cache . get ( cache_key , None )
2010-10-29 09:31:15 +08:00
2008-08-09 23:07:45 +08:00
if response is None :
request . _cache_update_cache = True
return None # No cache information available, need to rebuild.
2010-10-29 09:31:15 +08:00
# hit, return cached response
2008-08-09 23:07:45 +08:00
request . _cache_update_cache = False
return response
class CacheMiddleware ( UpdateCacheMiddleware , FetchFromCacheMiddleware ) :
"""
Cache middleware that provides basic behavior for many simple sites .
2008-08-16 01:47:03 +08:00
2008-08-09 23:07:45 +08:00
Also used as the hook point for the cache decorator , which is generated
using the decorator - from - middleware utility .
"""
2010-12-21 23:19:19 +08:00
def __init__ ( self , cache_timeout = None , cache_anonymous_only = None , * * kwargs ) :
# We need to differentiate between "provided, but using default value",
# and "not provided". If the value is provided using a default, then
# we fall back to system defaults. If it is not provided at all,
# we need to use middleware defaults.
2010-12-22 15:52:44 +08:00
cache_kwargs = { }
try :
self . key_prefix = kwargs . get ( ' key_prefix ' )
if self . key_prefix is not None :
cache_kwargs [ ' KEY_PREFIX ' ] = self . key_prefix
else :
self . key_prefix = ' '
except KeyError :
self . key_prefix = settings . CACHE_MIDDLEWARE_KEY_PREFIX
cache_kwargs [ ' KEY_PREFIX ' ] = self . key_prefix
2010-12-21 23:19:19 +08:00
try :
cache_alias = kwargs . get ( ' cache_alias ' )
if cache_alias is None :
cache_alias = DEFAULT_CACHE_ALIAS
2010-12-22 15:52:44 +08:00
if cache_timeout is not None :
cache_kwargs [ ' TIMEOUT ' ] = cache_timeout
2010-12-21 23:19:19 +08:00
except KeyError :
cache_alias = settings . CACHE_MIDDLEWARE_ALIAS
2010-12-22 15:52:44 +08:00
if cache_timeout is None :
cache_kwargs [ ' TIMEOUT ' ] = settings . CACHE_MIDDLEWARE_SECONDS
else :
cache_kwargs [ ' TIMEOUT ' ] = cache_timeout
2010-12-21 23:19:19 +08:00
2008-08-09 23:07:45 +08:00
if cache_anonymous_only is None :
self . cache_anonymous_only = getattr ( settings , ' CACHE_MIDDLEWARE_ANONYMOUS_ONLY ' , False )
else :
self . cache_anonymous_only = cache_anonymous_only
2010-12-21 23:19:19 +08:00
self . cache = get_cache ( cache_alias , * * cache_kwargs )
2010-12-22 15:52:44 +08:00
self . cache_timeout = self . cache . default_timeout