Fighting client-side caching in Django
I'm using the render_to_response shortcut and don't want to craft a specific Response object to add additional headers to prevent client-side caching.
I'd like to have a response that contains:
- Pragma: no-cache
- Cache-control : no-cache
- Cache-control: must-revalidate
And all the other nifty ways that browsers will hopefully interpret as directives to avoid caching.
Is there a no-cache 开发者_如何学Cmiddleware or something similar that can do the trick with minimal code intrusion?
You can achieve this using the cache_control decorator. Example from the documentation:
from django.views.decorators.cache import never_cache
@never_cache
def myview(request):
# ...
This approach (slight modification of L. De Leo's solution) with a custom middleware has worked well for me as a site wide solution:
from django.utils.cache import add_never_cache_headers
class DisableClientSideCachingMiddleware(object):
def process_response(self, request, response):
add_never_cache_headers(response)
return response
This makes use of add_never_cache_headers
.
If you want to combine this with UpdateCacheMiddleware
and FetchFromCacheMiddleware
, to enable server-side caching while disabling client-side caching, you need to add DisableClientSideCachingMiddleware
before everything else, like this:
MIDDLEWARE_CLASSES = (
'custom.middleware.DisableClientSideCachingMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
# ... all other middleware ...
'django.middleware.cache.FetchFromCacheMiddleware',
)
To supplement existing answers. Here is a decorator that adds additional headers to disable caching:
from django.views.decorators.cache import patch_cache_control
from functools import wraps
def never_ever_cache(decorated_function):
"""Like Django @never_cache but sets more valid cache disabling headers.
@never_cache only sets Cache-Control:max-age=0 which is not
enough. For example, with max-axe=0 Firefox returns cached results
of GET calls when it is restarted.
"""
@wraps(decorated_function)
def wrapper(*args, **kwargs):
response = decorated_function(*args, **kwargs)
patch_cache_control(
response, no_cache=True, no_store=True, must_revalidate=True,
max_age=0)
return response
return wrapper
And you can use it like:
class SomeView(View):
@method_decorator(never_ever_cache)
def get(self, request):
return HttpResponse('Hello')
I was scratching my head when the three magic meta
didn't work in Firefox and Safari.
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
Apparently it can happen because some browsers will ignore the client side meta
, so it should be handled at server side.
I tried all the answers from this post for my class based views (django==1.11.6
). But referring to answers from @Lorenzo and @Zags, I decided to write a middleware which I think is a simple one.
So adding to other good answers,
# middleware.py
class DisableBrowserCacheMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
response['Pragma'] = 'no-cache'
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response['Expires'] = '0'
return response
# settings.py
MIDDLEWARE = [
'myapp.middleware.DisableBrowserCacheMiddleware',
...
Actually writing my own middleware was easy enough:
from django.http import HttpResponse
class NoCacheMiddleware(object):
def process_response(self, request, response):
response['Pragma'] = 'no-cache'
response['Cache-Control'] = 'no-cache must-revalidate proxy-revalidate'
return response
Still doesn't really behave like i wanted but so neither does the @never_cache decorator
Regarding the Google Chrome browser (Version 34.0.1847.116 m) and the other browsers, I found that only the @cache_control
decorator is working. I use Django 1.6.2.
Use it like this:
@cache_control(max_age=0, no_cache=True, no_store=True, must_revalidate=True)
def view(request):
...
Here is a rewrite of @Meilo's answer for Django 1.10+:
from django.utils.cache import add_never_cache_headers
class DisableClientCachingMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
add_never_cache_headers(response)
return response
精彩评论