Fixed #612 - added cache control headers (thanks, hugo)

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1020 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jacob Kaplan-Moss 2005-10-29 17:00:20 +00:00
parent 67d490a61d
commit f12e324332
3 changed files with 90 additions and 2 deletions

View File

@ -21,6 +21,45 @@ import datetime, md5, re
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
cc_delim_re = re.compile(r'\s*,\s*')
def patch_cache_control(response, **kwargs):
"""
This function patches the Cache-Control header by adding all
keyword arguments to it. The transformation is as follows:
- all keyword parameter names are turned to lowercase and
all _ will be translated to -
- if the value of a parameter is True (exatly True, not just a
true value), only the parameter name is added to the header
- all other parameters are added with their value, after applying
str to it.
"""
def dictitem(s):
t = s.split('=',1)
if len(t) > 1:
return (t[0].lower().replace('-', '_'), t[1])
else:
return (t[0].lower().replace('-', '_'), True)
def dictvalue(t):
if t[1] == True:
return t[0]
else:
return t[0] + '=' + str(t[1])
if response.has_header('Cache-Control'):
print response['Cache-Control']
cc = cc_delim_re.split(response['Cache-Control'])
print cc
cc = dict([dictitem(el) for el in cc])
else:
cc = {}
for (k,v) in kwargs.items():
cc[k.replace('_', '-')] = v
cc = ', '.join([dictvalue(el) for el in cc.items()])
response['Cache-Control'] = cc
vary_delim_re = re.compile(r',\s*') vary_delim_re = re.compile(r',\s*')
def patch_response_headers(response, cache_timeout=None): def patch_response_headers(response, cache_timeout=None):
@ -43,8 +82,7 @@ def patch_response_headers(response, cache_timeout=None):
response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT') response['Last-Modified'] = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
if not response.has_header('Expires'): if not response.has_header('Expires'):
response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT') response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT')
if not response.has_header('Cache-Control'): patch_cache_control(response, max_age=cache_timeout)
response['Cache-Control'] = 'max-age=%d' % cache_timeout
def patch_vary_headers(response, newheaders): def patch_vary_headers(response, newheaders):
""" """

View File

@ -10,8 +10,24 @@ example, as that is unique across a Django project.
Additionally, all headers from the response's Vary header will be taken into Additionally, all headers from the response's Vary header will be taken into
account on caching -- just like the middleware does. account on caching -- just like the middleware does.
""" """
import re
from django.utils.decorators import decorator_from_middleware from django.utils.decorators import decorator_from_middleware
from django.utils.cache import patch_cache_control
from django.middleware.cache import CacheMiddleware from django.middleware.cache import CacheMiddleware
cache_page = decorator_from_middleware(CacheMiddleware) cache_page = decorator_from_middleware(CacheMiddleware)
def cache_control(**kwargs):
def _cache_controller(viewfunc):
def _cache_controlled(request, *args, **kw):
response = viewfunc(request, *args, **kw)
patch_cache_control(response, **kwargs)
return response
return _cache_controlled
return _cache_controller

View File

@ -270,6 +270,40 @@ and a list/tuple of header names as its second argument.
.. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 .. _`HTTP Vary headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44
Controlling cache: Using Vary headers
=====================================
Another problem with caching is the privacy of data, and the question where data can
be stored in a cascade of caches. A user usually faces two kinds of caches: his own
browser cache (a private cache) and his providers cache (a public cache). A public cache
is used by multiple users and controlled by someone else. This poses problems with private
(in the sense of sensitive) data - you don't want your social security number or your
banking account numbers stored in some public cache. So web applications need a way
to tell the caches what data is private and what is public.
Other aspects are the definition how long a page should be cached at max, or wether the
cache should allways check for newer versions and only deliver the cache content when
there were no changes (some caches might deliver cached content even if the server page
changed - just because the cache copy isn't yet expired).
So there are a multitude of options you can control for your pages. This is where the
Cache-Control header (more infos in `HTTP Cache-Control headers`_) comes in. The usage
is quite simple::
@cache_control(private=True, must_revalidate=True, max_age=3600)
def my_view(request):
...
This would define the view as private, to be revalidated on every access and cache
copies will only be stored for 3600 seconds at max.
The caching middleware already set's this header up with a max-age of the CACHE_MIDDLEWARE_SETTINGS
setting. And the cache_page decorator does the same. The cache_control decorator correctly merges
different values into one big header, though. But you should take into account that middlewares
might overwrite some of your headers or set their own defaults if you don't give that header yourself.
.. _`HTTP Cache-Control headers`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
Other optimizations Other optimizations
=================== ===================