Added django.middleware.cache, which lets you cache an entire Django-powered site by adding a line to your settings
git-svn-id: http://code.djangoproject.com/svn/django/trunk@178 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0944653673
commit
8fd94405b5
|
@ -0,0 +1,88 @@
|
|||
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
|
Loading…
Reference in New Issue