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
2011-03-02 20:47:36 +08:00
* Only 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
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
2013-05-18 22:10:14 +08:00
import warnings
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
2011-02-17 12:35:26 +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
2011-01-24 22:24:35 +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 )
2011-01-24 14:36:31 +08:00
self . cache_alias = settings . CACHE_MIDDLEWARE_ALIAS
self . cache = get_cache ( self . cache_alias )
2005-07-19 03:07:37 +08:00
2011-02-17 12:35:26 +08:00
def _session_accessed ( self , request ) :
try :
return request . session . accessed
except AttributeError :
return False
2011-02-01 08:20:31 +08:00
def _should_update_cache ( self , request , response ) :
if not hasattr ( request , ' _cache_update_cache ' ) or not request . _cache_update_cache :
return False
2011-02-17 12:35:26 +08:00
# If the session has not been accessed otherwise, we don't want to
# cause it to be accessed here. If it hasn't been accessed, then the
# user's logged-in status has not affected the response anyway.
if self . cache_anonymous_only and self . _session_accessed ( request ) :
2011-02-01 08:20:31 +08:00
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 request . user . is_authenticated ( ) :
# Don't cache user-variable requests from authenticated users.
return False
return True
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. """
2011-02-01 08:20:31 +08:00
if not self . _should_update_cache ( request , response ) :
2005-10-09 08:55:08 +08:00
# We don't need to update the cache, just return.
return response
2012-12-25 03:25:02 +08:00
if response . streaming or response . status_code != 200 :
2005-10-09 08:55:08 +08:00
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 )
2011-01-24 22:24:35 +08:00
if hasattr ( response , ' render ' ) and callable ( response . render ) :
response . add_post_render_callback (
lambda r : self . cache . set ( cache_key , r , timeout )
)
else :
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
2011-01-24 14:36:31 +08:00
self . cache_alias = settings . CACHE_MIDDLEWARE_ALIAS
self . cache = get_cache ( self . cache_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 .
"""
2011-03-02 20:47:36 +08:00
if not request . method in ( ' GET ' , ' HEAD ' ) :
2008-08-09 23:07:45 +08:00
request . _cache_update_cache = False
return None # Don't bother checking the cache.
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 = { }
2011-01-24 14:36:31 +08:00
2010-12-22 15:52:44 +08:00
try :
2011-01-24 14:36:31 +08:00
self . key_prefix = kwargs [ ' key_prefix ' ]
2010-12-22 15:52:44 +08:00
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
2011-01-24 14:36:31 +08:00
2010-12-21 23:19:19 +08:00
try :
2011-01-24 14:36:31 +08:00
self . cache_alias = kwargs [ ' cache_alias ' ]
if self . cache_alias is None :
self . 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 :
2011-01-24 14:36:31 +08:00
self . 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
2013-05-18 22:10:14 +08:00
if self . cache_anonymous_only :
msg = " CACHE_MIDDLEWARE_ANONYMOUS_ONLY has been deprecated and will be removed in Django 1.8. "
2013-06-30 00:34:41 +08:00
warnings . warn ( msg , DeprecationWarning , stacklevel = 1 )
2013-05-18 22:10:14 +08:00
2011-01-24 14:36:31 +08:00
self . cache = get_cache ( self . cache_alias , * * cache_kwargs )
2010-12-22 15:52:44 +08:00
self . cache_timeout = self . cache . default_timeout