django1/django/middleware/cache.py

89 lines
3.6 KiB
Python
Raw Normal View History

from django.conf import settings
from django.core.cache import cache
from django.utils.httpwrappers import HttpResponseNotModified
from django.utils.text import compress_string
import datetime, md5
class CacheMiddleware:
"""
Cache middleware. If this is enabled, each Django-powered page will be
cached for CACHE_MIDDLEWARE_SECONDS seconds. Cache is based on URLs. Pages
with GET or POST parameters are not cached.
If the cache is shared across multiple sites using the same Django
installation, set the CACHE_MIDDLEWARE_KEY_PREFIX to the name of the site,
or some other string that is unique to this Django instance, to prevent key
collisions.
This middleware will also make the following optimizations:
* If the CACHE_MIDDLEWARE_GZIP setting is True, the content will be
gzipped.
* ETags will be added, using a simple MD5 hash of the page's content.
"""
def process_request(self, request):
"""
Checks whether the page is already cached. If it is, returns the cached
version. Also handles ETag stuff.
"""
if request.GET or request.POST:
request._cache_middleware_set_cache = False
return None # Don't bother checking the cache.
accept_encoding = ''
if settings.CACHE_MIDDLEWARE_GZIP:
try:
accept_encoding = request.META['HTTP_ACCEPT_ENCODING']
except KeyError:
pass
accepts_gzip = 'gzip' in accept_encoding
request._cache_middleware_accepts_gzip = accepts_gzip
# This uses the same cache_key as views.decorators.cache.cache_page,
# so the cache can be shared.
cache_key = 'views.decorators.cache.cache_page.%s.%s.%s' % \
(settings.CACHE_MIDDLEWARE_KEY_PREFIX, request.path, accepts_gzip)
request._cache_middleware_key = cache_key
response = cache.get(cache_key, None)
if response is None:
request._cache_middleware_set_cache = True
return None
else:
request._cache_middleware_set_cache = False
# Logic is from http://simon.incutio.com/archive/2003/04/23/conditionalGet
try:
if_none_match = request.META['HTTP_IF_NONE_MATCH']
except KeyError:
if_none_match = None
try:
if_modified_since = request.META['HTTP_IF_MODIFIED_SINCE']
except KeyError:
if_modified_since = None
if if_none_match is None and if_modified_since is None:
pass
elif if_none_match is not None and response['ETag'] != if_none_match:
pass
elif if_modified_since is not None and response['Last-Modified'] != if_modified_since:
pass
else:
return HttpResponseNotModified()
return response
def process_response(self, request, response):
"""
Sets the cache, if needed.
"""
if request._cache_middleware_set_cache:
content = response.get_content_as_string('utf-8')
if request._cache_middleware_accepts_gzip:
content = compress_string(content)
response.content = content
response['Content-Encoding'] = 'gzip'
response['ETag'] = md5.new(content).hexdigest()
response['Content-Length'] = '%d' % len(content)
response['Last-Modified'] = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
cache.set(request._cache_middleware_key, response, settings.CACHE_MIDDLEWARE_SECONDS)
return response