89 lines
3.6 KiB
Python
89 lines
3.6 KiB
Python
|
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
|