0

I've set up page level caching for many of our pages. However once in a while an admin user logs in to preview potential changes to the site.

Is there a way to disable page level caching just for these users?

I read through the docs but I didn't see anything.

Update: Here's my attempt based on v1k45's answer:

from django.middleware.cache import FetchFromCacheMiddleware


logger = logging.getLogger(__name__)


class ExceptImpersonateFetchFromCacheMiddleware(FetchFromCacheMiddleware):
    def process_request(self, request):
        # Break out of caching is we're using impersonate
        if request.user and hasattr(request.user, 'is_impersonate') and request.user.is_impersonate:
            logger.warning("Skipping cache_page for user %s because it is impersonation" % str(request.user))
            request._cache_update_cache = False
            return None
        # Normal flow:
        return super(ExceptImpersonateFetchFromCacheMiddleware, self).process_request(request)
Greg
  • 45,306
  • 89
  • 231
  • 297

1 Answers1

1

You can extend the CacheMiddleware provided by django such that the admin users always see fresh content instead of cached.

Have a look at the source code for FetchFromCacheMiddleware, you can see this code snippet:

def process_request(self, request):
    [...]
    if request.method not in ('GET', 'HEAD'):
        request._cache_update_cache = False
        return None  # Don't bother checking the cache.

The if condition here tells django to skip cache and don't update the existing cached data if the request method is not GET or HEAD.

Similarly, you can add a check where you skip the cache if the user is an admin. Roughly it will look like this:

def process_request(self, request):
    [...snip..]
    if request.user.is_staff:
        request._cache_update_cache = False
        return None  # Don't bother checking the cache.

UPDATE: The cache_page decorator uses django's CacheMiddleware which extends the functionality of FetchFromCacheMiddleware and UpdateCacheMiddleware.

Now you'll have to make your own version of CacheMiddleware and cache_page decorator. This custom_cache_page decorator will call your CustomCacheMiddleware which extends your CustomFetchFromCacheMiddleware and django's UpdateCacheMiddleware.

After you have completed the CustomCacheMiddleware, you'll have to replace django's CacheMiddleware with your own. This can be done by changing MIDDLEWARE_CLASSES tuple in settings.py.

v1k45
  • 8,070
  • 2
  • 30
  • 38
  • This looks very promising! Thanks! What's the best way to do this? Am I modifying Django's own source code, or is there a smarter way? – Greg Jan 16 '17 at 17:33
  • You are not modifying django's source code, you are just replacing a middleware provided by django which is meant to be replaceable any time. All you have to do is put your extended class' python path in your settings.py `MIDDLEWARE_CLASSES`. – v1k45 Jan 16 '17 at 17:41
  • Are you saying to name my new class "FetchFromCacheMiddleware" to override Django's version? I don't see "FetchFromCacheMiddleware" mentioned in settings.py in MIDDLEWARE_CLASSES. – Greg Jan 16 '17 at 20:29
  • (Also I put my code in the question, does that look about right) – Greg Jan 16 '17 at 20:37
  • Hmm, upon further reading, the FetchFromCacheMiddleware is only for entire site caching, not the cache_page decorator? – Greg Jan 16 '17 at 21:11
  • Sorry, i thought you asked about per-site cache. You'll have to create a custom `cache_page` decorator. See the updated answer. – v1k45 Jan 17 '17 at 03:54