| | 1 | """ |
|---|
| | 2 | Cache middleware. If enabled, each Django-powered page will be cached based on |
|---|
| | 3 | URL. The cannonical way to enable cache middleware is to set |
|---|
| | 4 | ``UpdateCacheMiddleware`` as your first piece of middleware, and |
|---|
| | 5 | ``FetchFromCacheMiddleware`` as the last:: |
|---|
| | 6 | |
|---|
| | 7 | MIDDLEWARE_CLASSES = [ |
|---|
| | 8 | 'django.middleware.cache.UpdateCacheMiddleware', |
|---|
| | 9 | ... |
|---|
| | 10 | 'django.middleware.cache.FetchFromCacheMiddleware' |
|---|
| | 11 | ] |
|---|
| | 12 | |
|---|
| | 13 | This is counter-intuitive, but correct: ``UpdateCacheMiddleware`` needs to run |
|---|
| | 14 | last during the response phase, which processes middleware bottom-up; |
|---|
| | 15 | ``FetchFromCacheMiddleware`` needs to run last during the request phase, which |
|---|
| | 16 | processes middleware top-down. |
|---|
| | 17 | |
|---|
| | 18 | The single-class ``CacheMiddleware`` can be used for some simple sites. However, |
|---|
| | 19 | if any other peice of middleware needs to affect the cache key, you'll need to |
|---|
| | 20 | use the two-part UpdateCacheMiddleware and FetchFromCacheMiddleware. This'll |
|---|
| | 21 | most often happen when you're using Django's LocaleMiddleware. |
|---|
| | 22 | |
|---|
| | 23 | More details about how the caching works: |
|---|
| | 24 | |
|---|
| | 25 | * Only parameter-less GET or HEAD-requests with status code 200 are cached. |
|---|
| | 26 | |
|---|
| | 27 | * The number of seconds each page is stored for is set by the "max-age" section |
|---|
| | 28 | of the response's "Cache-Control" header, falling back to the |
|---|
| | 29 | CACHE_MIDDLEWARE_SECONDS setting if the section was not found. |
|---|
| | 30 | |
|---|
| | 31 | * If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests |
|---|
| | 32 | (i.e., those not made by a logged-in user) will be cached. This is a simple |
|---|
| | 33 | and effective way of avoiding the caching of the Django admin (and any other |
|---|
| | 34 | user-specific content). |
|---|
| | 35 | |
|---|
| | 36 | * This middleware expects that a HEAD request is answered with a response |
|---|
| | 37 | exactly like the corresponding GET request. |
|---|
| | 38 | |
|---|
| | 39 | * When a hit occurs, a shallow copy of the original response object is returned |
|---|
| | 40 | from process_request. |
|---|
| | 41 | |
|---|
| | 42 | * Pages will be cached based on the contents of the request headers listed in |
|---|
| | 43 | the response's "Vary" header. |
|---|
| | 44 | |
|---|
| | 45 | * This middleware also sets ETag, Last-Modified, Expires and Cache-Control |
|---|
| | 46 | headers on the response object. |
|---|
| | 47 | |
|---|
| | 48 | """ |
|---|
| | 49 | |
|---|
| 7 | | Cache middleware. If this is enabled, each Django-powered page will be |
|---|
| 8 | | cached (based on URLs). |
|---|
| | 56 | Response-phase cache middleware that updates the cache if the response is |
|---|
| | 57 | cacheable. |
|---|
| | 58 | |
|---|
| | 59 | Must be used as part of the two-part update/fetch cache middleware. |
|---|
| | 60 | UpdateCacheMiddleware must be the first piece of middleware in |
|---|
| | 61 | MIDDLEWARE_CLASSES so that it'll get called last during the response phase. |
|---|
| | 62 | """ |
|---|
| | 63 | def __init__(self): |
|---|
| | 64 | self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |
|---|
| | 65 | self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |
|---|
| | 66 | self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |
|---|
| 10 | | Only parameter-less GET or HEAD-requests with status code 200 are cached. |
|---|
| | 68 | def process_response(self, request, response): |
|---|
| | 69 | """Sets the cache, if needed.""" |
|---|
| | 70 | if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache: |
|---|
| | 71 | # We don't need to update the cache, just return. |
|---|
| | 72 | return response |
|---|
| | 73 | if request.method != 'GET': |
|---|
| | 74 | # This is a stronger requirement than above. It is needed |
|---|
| | 75 | # because of interactions between this middleware and the |
|---|
| | 76 | # HTTPMiddleware, which throws the body of a HEAD-request |
|---|
| | 77 | # away before this middleware gets a chance to cache it. |
|---|
| | 78 | return response |
|---|
| | 79 | if not response.status_code == 200: |
|---|
| | 80 | return response |
|---|
| | 81 | # Try to get the timeout from the "max-age" section of the "Cache- |
|---|
| | 82 | # Control" header before reverting to using the default cache_timeout |
|---|
| | 83 | # length. |
|---|
| | 84 | timeout = get_max_age(response) |
|---|
| | 85 | if timeout == None: |
|---|
| | 86 | timeout = self.cache_timeout |
|---|
| | 87 | elif timeout == 0: |
|---|
| | 88 | # max-age was set to 0, don't bother caching. |
|---|
| | 89 | return response |
|---|
| | 90 | patch_response_headers(response, timeout) |
|---|
| | 91 | cache_key = learn_cache_key(request, response, timeout, self.key_prefix) |
|---|
| | 92 | cache.set(cache_key, response, timeout) |
|---|
| | 93 | return response |
|---|
| 12 | | The number of seconds each page is stored for is set by the |
|---|
| 13 | | "max-age" section of the response's "Cache-Control" header, falling back to |
|---|
| 14 | | the CACHE_MIDDLEWARE_SECONDS setting if the section was not found. |
|---|
| 15 | | |
|---|
| 16 | | If CACHE_MIDDLEWARE_ANONYMOUS_ONLY is set to True, only anonymous requests |
|---|
| 17 | | (i.e., those not made by a logged-in user) will be cached. This is a |
|---|
| 18 | | simple and effective way of avoiding the caching of the Django admin (and |
|---|
| 19 | | any other user-specific content). |
|---|
| 20 | | |
|---|
| 21 | | This middleware expects that a HEAD request is answered with a response |
|---|
| 22 | | exactly like the corresponding GET request. |
|---|
| 23 | | |
|---|
| 24 | | When a hit occurs, a shallow copy of the original response object is |
|---|
| 25 | | returned from process_request. |
|---|
| 26 | | |
|---|
| 27 | | Pages will be cached based on the contents of the request headers |
|---|
| 28 | | listed in the response's "Vary" header. This means that pages shouldn't |
|---|
| 29 | | change their "Vary" header. |
|---|
| 30 | | |
|---|
| 31 | | This middleware also sets ETag, Last-Modified, Expires and Cache-Control |
|---|
| 32 | | headers on the response object. |
|---|
| | 95 | class FetchFromCacheMiddleware(object): |
|---|
| 34 | | def __init__(self, cache_timeout=None, key_prefix=None, cache_anonymous_only=None): |
|---|
| 35 | | self.cache_timeout = cache_timeout |
|---|
| 36 | | if cache_timeout is None: |
|---|
| 37 | | self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |
|---|
| 38 | | self.key_prefix = key_prefix |
|---|
| 39 | | if key_prefix is None: |
|---|
| 40 | | self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |
|---|
| 41 | | if cache_anonymous_only is None: |
|---|
| 42 | | self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |
|---|
| 43 | | else: |
|---|
| 44 | | self.cache_anonymous_only = cache_anonymous_only |
|---|
| 45 | | |
|---|
| | 97 | Request-phase cache middleware that fetches a page from the cache. |
|---|
| | 98 | |
|---|
| | 99 | Must be used as part of the two-part update/fetch cache middleware. |
|---|
| | 100 | FetchFromCacheMiddleware must be the last piece of middleware in |
|---|
| | 101 | MIDDLEWARE_CLASSES so that it'll get called last during the request phase. |
|---|
| | 102 | """ |
|---|
| | 103 | def __init__(self): |
|---|
| | 104 | self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |
|---|
| | 105 | self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |
|---|
| | 106 | self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |
|---|
| | 107 | |
|---|
| 72 | | def process_response(self, request, response): |
|---|
| 73 | | "Sets the cache, if needed." |
|---|
| 74 | | if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache: |
|---|
| 75 | | # We don't need to update the cache, just return. |
|---|
| 76 | | return response |
|---|
| 77 | | if request.method != 'GET': |
|---|
| 78 | | # This is a stronger requirement than above. It is needed |
|---|
| 79 | | # because of interactions between this middleware and the |
|---|
| 80 | | # HTTPMiddleware, which throws the body of a HEAD-request |
|---|
| 81 | | # away before this middleware gets a chance to cache it. |
|---|
| 82 | | return response |
|---|
| 83 | | if not response.status_code == 200: |
|---|
| 84 | | return response |
|---|
| 85 | | # Try to get the timeout from the "max-age" section of the "Cache- |
|---|
| 86 | | # Control" header before reverting to using the default cache_timeout |
|---|
| 87 | | # length. |
|---|
| 88 | | timeout = get_max_age(response) |
|---|
| 89 | | if timeout == None: |
|---|
| 90 | | timeout = self.cache_timeout |
|---|
| 91 | | elif timeout == 0: |
|---|
| 92 | | # max-age was set to 0, don't bother caching. |
|---|
| 93 | | return response |
|---|
| 94 | | patch_response_headers(response, timeout) |
|---|
| 95 | | cache_key = learn_cache_key(request, response, timeout, self.key_prefix) |
|---|
| 96 | | cache.set(cache_key, response, timeout) |
|---|
| 97 | | return response |
|---|
| | 137 | class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware): |
|---|
| | 138 | """ |
|---|
| | 139 | Cache middleware that provides basic behavior for many simple sites. |
|---|
| | 140 | |
|---|
| | 141 | Also used as the hook point for the cache decorator, which is generated |
|---|
| | 142 | using the decorator-from-middleware utility. |
|---|
| | 143 | """ |
|---|
| | 144 | def __init__(self, cache_timeout=None, key_prefix=None, cache_anonymous_only=None): |
|---|
| | 145 | self.cache_timeout = cache_timeout |
|---|
| | 146 | if cache_timeout is None: |
|---|
| | 147 | self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS |
|---|
| | 148 | self.key_prefix = key_prefix |
|---|
| | 149 | if key_prefix is None: |
|---|
| | 150 | self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX |
|---|
| | 151 | if cache_anonymous_only is None: |
|---|
| | 152 | self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False) |
|---|
| | 153 | else: |
|---|
| | 154 | self.cache_anonymous_only = cache_anonymous_only |
|---|
| | 155 | |
|---|