cache middleware if enabled each djangopowered page will be cached based on url the canonical way to enable cache middleware is to set updatecachemiddleware as your first piece of middleware and fetchfromcachemiddleware as the last middleware django middleware cache updatecachemiddleware django middleware cache fetchfromcachemiddleware this is counterintuitive but correct updatecachemiddleware needs to run last during the response phase which processes middleware bottomup fetchfromcachemiddleware needs to run last during the request phase which processes middleware topdown the singleclass 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 twopart updatecachemiddleware and fetchfromcachemiddleware this ll most often happen when you re using django s localemiddleware more details about how the caching works only get or headrequests with status code 200 are cached the number of seconds each page is stored for is set by the maxage section of the response s cachecontrol header falling back to the cachemiddlewareseconds setting if the section was not found this middleware expects that a head request is answered with the same response headers exactly like the corresponding get request when a hit occurs a shallow copy of the original response object is returned from processrequest pages will be cached based on the contents of the request headers listed in the response s vary header this middleware also sets etag lastmodified expires and cachecontrol headers on the response object responsephase cache middleware that updates the cache if the response is cacheable must be used as part of the twopart updatefetch cache middleware updatecachemiddleware must be the first piece of middleware in middleware so that it ll get called last during the response phase set the cache if needed if not self shouldupdatecacherequest response we don t need to update the cache just return return response if response streaming or response statuscode not in 200 304 return response don t cache responses that set a userspecific and maybe security sensitive cookie in response to a cookieless request if not request cookies and response cookies and hasvaryheaderresponse cookie return response don t cache a response with cachecontrol private if private in response getcachecontrol return response page timeout takes precedence over the maxage and the default cache timeout timeout self pagetimeout if timeout is none the timeout from the maxage section of the cachecontrol header takes precedence over the default cache timeout timeout getmaxageresponse if timeout is none timeout self cachetimeout elif timeout 0 maxage was set to 0 don t cache return response patchresponseheadersresponse timeout if timeout and response statuscode 200 cachekey learncachekey request response timeout self keyprefix cacheself cache if hasattrresponse render and callableresponse render response addpostrendercallback lambda r self cache setcachekey r timeout else self cache setcachekey response timeout return response class fetchfromcachemiddlewaremiddlewaremixin def initself getresponse super initgetresponse self keyprefix settings cachemiddlewarekeyprefix self cachealias settings cachemiddlewarealias property def cacheself return cachesself cachealias def processrequestself request if request method not in get head request cacheupdatecache false return none don t bother checking the cache try and get the cached get response cachekey getcachekeyrequest self keyprefix get cacheself cache if cachekey is none request cacheupdatecache true return none no cache information available need to rebuild response self cache getcachekey 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 cachekey getcachekey request self keyprefix head cacheself cache response self cache getcachekey if response is none request cacheupdatecache true return none no cache information available need to rebuild hit return cached response request cacheupdatecache false return response class cachemiddlewareupdatecachemiddleware fetchfromcachemiddleware def initself getresponse cachetimeoutnone pagetimeoutnone kwargs super initgetresponse 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 try keyprefix kwargskeyprefix if keyprefix is none keyprefix self keyprefix keyprefix except keyerror pass try cachealias kwargscachealias if cachealias is none cachealias defaultcachealias self cachealias cachealias except keyerror pass if cachetimeout is not none self cachetimeout cachetimeout self pagetimeout pagetimeout response phase cache middleware that updates the cache if the response is cacheable must be used as part of the two part update fetch cache middleware updatecachemiddleware must be the first piece of middleware in middleware so that it ll get called last during the response phase set the cache if needed we don t need to update the cache just return don t cache responses that set a user specific and maybe security sensitive cookie in response to a cookie less request don t cache a response with cache control private page timeout takes precedence over the max age and the default cache timeout the timeout from the max age section of the cache control header takes precedence over the default cache timeout max age was set to 0 don t cache request phase cache middleware that fetches a page from the cache must be used as part of the two part update fetch cache middleware fetchfromcachemiddleware must be the last piece of middleware in middleware so that it ll get called last during the request phase check whether the page is already cached and return the cached version if available don t bother checking the cache try and get the cached get response no cache information available need to rebuild if it wasn t found and we are looking for a head try looking just for that no cache information available need to rebuild hit return cached response cache middleware that provides basic behavior for many simple sites also used as the hook point for the cache decorator which is generated using the decorator from middleware utility 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
from django.conf import settings
from django.core.cache import DEFAULT_CACHE_ALIAS, caches
from django.utils.cache import (
    get_cache_key,
    get_max_age,
    has_vary_header,
    learn_cache_key,
    patch_response_headers,
)
from django.utils.deprecation import MiddlewareMixin


class UpdateCacheMiddleware(MiddlewareMixin):
    

    def __init__(self, get_response):
        super().__init__(get_response)
        self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
        self.page_timeout = None
        self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
        self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS

    @property
    def cache(self):
        return caches[self.cache_alias]

    def _should_update_cache(self, request, response):
        return hasattr(request, "_cache_update_cache") and request._cache_update_cache

    def process_response(self, request, response):
        
        if not self._should_update_cache(request, response):
            
            return response

        if response.streaming or response.status_code not in (200, 304):
            return response

        
        
        if (
            not request.COOKIES
            and response.cookies
            and has_vary_header(response, "Cookie")
        ):
            return response

        
        if "private" in response.get("Cache-Control", ()):
            return response

        
        
        timeout = self.page_timeout
        if timeout is None:
            
            
            timeout = get_max_age(response)
            if timeout is None:
                timeout = self.cache_timeout
            elif timeout == 0:
                
                return response
        patch_response_headers(response, timeout)
        if timeout and response.status_code == 200:
            cache_key = learn_cache_key(
                request, response, timeout, self.key_prefix, cache=self.cache
            )
            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)
        return response


class FetchFromCacheMiddleware(MiddlewareMixin):
    

    def __init__(self, get_response):
        super().__init__(get_response)
        self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
        self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS

    @property
    def cache(self):
        return caches[self.cache_alias]

    def process_request(self, request):
        
        if request.method not in ("GET", "HEAD"):
            request._cache_update_cache = False
            return None  

        
        cache_key = get_cache_key(request, self.key_prefix, "GET", cache=self.cache)
        if cache_key is None:
            request._cache_update_cache = True
            return None  
        response = self.cache.get(cache_key)
        
        if response is None and request.method == "HEAD":
            cache_key = get_cache_key(
                request, self.key_prefix, "HEAD", cache=self.cache
            )
            response = self.cache.get(cache_key)

        if response is None:
            request._cache_update_cache = True
            return None  

        
        request._cache_update_cache = False
        return response


class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
    

    def __init__(self, get_response, cache_timeout=None, page_timeout=None, **kwargs):
        super().__init__(get_response)
        
        
        
        

        try:
            key_prefix = kwargs["key_prefix"]
            if key_prefix is None:
                key_prefix = ""
            self.key_prefix = key_prefix
        except KeyError:
            pass
        try:
            cache_alias = kwargs["cache_alias"]
            if cache_alias is None:
                cache_alias = DEFAULT_CACHE_ALIAS
            self.cache_alias = cache_alias
        except KeyError:
            pass

        if cache_timeout is not None:
            self.cache_timeout = cache_timeout
        self.page_timeout = page_timeout