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:
parent
67d490a61d
commit
f12e324332
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue