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
2008-08-09 23:07:45 +08:00
* This middleware expects that a HEAD request is answered with a response
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
from django . core . cache import cache
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 )
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
2006-06-20 12:34:13 +08:00
if request . method != ' GET ' :
2005-10-09 08:55:08 +08:00
# This is a stronger requirement than above. It is needed
# because of interactions between this middleware and the
# HTTPMiddleware, which throws the body of a HEAD-request
# away before this middleware gets a chance to cache it.
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 :
cache_key = learn_cache_key ( request , response , timeout , self . key_prefix )
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 )
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.
cache_key = get_cache_key ( request , self . key_prefix )
if cache_key is None :
request . _cache_update_cache = True
return None # No cache information available, need to rebuild.
response = cache . get ( cache_key , None )
if response is None :
request . _cache_update_cache = True
return None # No cache information available, need to rebuild.
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 .
"""
def __init__ ( self , cache_timeout = None , key_prefix = None , cache_anonymous_only = None ) :
self . cache_timeout = cache_timeout
if cache_timeout is None :
self . cache_timeout = settings . CACHE_MIDDLEWARE_SECONDS
self . key_prefix = key_prefix
if key_prefix is None :
self . key_prefix = settings . CACHE_MIDDLEWARE_KEY_PREFIX
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