From d4abd6fb5265d711056a4350745a870ef39c5439 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Sun, 23 Oct 2005 22:43:54 +0000 Subject: Small massaging of docs/model-api.txt git-svn-id: http://code.djangoproject.com/svn/django/trunk@1006 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/model-api.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/model-api.txt b/docs/model-api.txt index fa6d8f10e6..3522585e7a 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -750,11 +750,12 @@ Here's a list of all possible ``META`` options. No options are required. Adding ``permissions`` Extra permissions to enter into the permissions table when creating this object. Add, delete and change permissions are automatically created for - each object. This option specifies extra permissions:: + each object that has ``admin`` set. This example specifies an extra + permission, ``can_deliver_pizzas``:: permissions = (("can_deliver_pizzas", "Can deliver pizzas"),) - This is a list of 2-tuples of + This is a list or tuple of 2-tuples in the format ``(permission_code, human_readable_permission_name)``. ``unique_together`` -- cgit v1.3 From f12e3243326a2b6b0d09206b373b34e028eab25c Mon Sep 17 00:00:00 2001 From: Jacob Kaplan-Moss Date: Sat, 29 Oct 2005 17:00:20 +0000 Subject: Fixed #612 - added cache control headers (thanks, hugo) git-svn-id: http://code.djangoproject.com/svn/django/trunk@1020 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/utils/cache.py | 42 ++++++++++++++++++++++++++++++++++++++-- django/views/decorators/cache.py | 16 +++++++++++++++ docs/cache.txt | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/django/utils/cache.py b/django/utils/cache.py index fcd0825a22..631ea8f08d 100644 --- a/django/utils/cache.py +++ b/django/utils/cache.py @@ -21,6 +21,45 @@ import datetime, md5, re from django.conf import settings 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*') 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') if not response.has_header('Expires'): response['Expires'] = expires.strftime('%a, %d %b %Y %H:%M:%S GMT') - if not response.has_header('Cache-Control'): - response['Cache-Control'] = 'max-age=%d' % cache_timeout + patch_cache_control(response, max_age=cache_timeout) def patch_vary_headers(response, newheaders): """ diff --git a/django/views/decorators/cache.py b/django/views/decorators/cache.py index 09f9a0139f..f86372cf4e 100644 --- a/django/views/decorators/cache.py +++ b/django/views/decorators/cache.py @@ -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 account on caching -- just like the middleware does. """ +import re from django.utils.decorators import decorator_from_middleware +from django.utils.cache import patch_cache_control from django.middleware.cache import 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 + diff --git a/docs/cache.txt b/docs/cache.txt index f15da2660b..7db42db249 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -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 +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 =================== -- cgit v1.3 From 2822f71d08f3a94a3e26bb80fa1dbcef7bf2f1db Mon Sep 17 00:00:00 2001 From: Jacob Kaplan-Moss Date: Sat, 29 Oct 2005 17:05:19 +0000 Subject: Fixed #140: memcached backends may now use multiple servers git-svn-id: http://code.djangoproject.com/svn/django/trunk@1021 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/cache.py | 6 ++++-- docs/cache.txt | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/django/core/cache.py b/django/core/cache.py index 6391304158..caeb315f05 100644 --- a/django/core/cache.py +++ b/django/core/cache.py @@ -13,7 +13,9 @@ settings.CACHE_BACKEND and use that to create and load a cache object. The CACHE_BACKEND setting is a quasi-URI; examples are: memcached://127.0.0.1:11211/ A memcached backend; the server is running - on localhost port 11211. + on localhost port 11211. You can use + multiple memcached servers by separating + them with semicolons. db://tablename/ A database backend in a table named "tablename". This table should be created @@ -134,7 +136,7 @@ else: "Memcached cache backend." def __init__(self, server, params): _Cache.__init__(self, params) - self._cache = memcache.Client([server]) + self._cache = memcache.Client(server.split(';')) def get(self, key, default=None): val = self._cache.get(key) diff --git a/docs/cache.txt b/docs/cache.txt index 7db42db249..c1b1352bca 100644 --- a/docs/cache.txt +++ b/docs/cache.txt @@ -29,7 +29,9 @@ Examples: CACHE_BACKEND Explanation ============================== =========================================== memcached://127.0.0.1:11211/ A memcached backend; the server is running - on localhost port 11211. + on localhost port 11211. You can use + multiple memcached servers by separating + them with semicolons. db://tablename/ A database backend in a table named "tablename". This table should be created -- cgit v1.3 From fb55717a09fb7f92c76d1af23b2717b7a0610d03 Mon Sep 17 00:00:00 2001 From: Jacob Kaplan-Moss Date: Sun, 30 Oct 2005 14:35:44 +0000 Subject: Documented {{{singular}}} argument for m2m relationships (fixes #664). git-svn-id: http://code.djangoproject.com/svn/django/trunk@1025 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/model-api.txt | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'docs') diff --git a/docs/model-api.txt b/docs/model-api.txt index 3522585e7a..edf94dd17c 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -621,6 +621,14 @@ the relationship should work. All are optional: vertically). ``limit_choices_to`` See the description under ``ForeignKey`` above. + + ``singular`` The singular name of the field. Use to name the ``get_*`` + methods: in the example above, Django gives the ``Pizza`` + objects a ``get_topping_list()`` method, where ``topping`` + is the default ``singular`` value derived from the lowercase + version of the class being linked to. Use the singular + parameter to change this, which is if you want one model to + have multiple ``ManyToMany`` relationships to another model. ======================= ============================================================ One-to-one relationships -- cgit v1.3