Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
  • Loading branch information...
commit 8fd94405b51298e84fea604f339b8147df583270 1 parent 0944653
@adrianholovaty adrianholovaty authored
Showing with 88 additions and 0 deletions.
  1. +88 −0 django/middleware/cache.py
View
88 django/middleware/cache.py
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.