Code

Ticket #15499: allow-cache-control-private-override-4.diff

File allow-cache-control-private-override-4.diff, 4.6 KB (added by AndiDog, 3 years ago)

Update for recent trunk

Line 
1Index: django/utils/cache.py
2===================================================================
3--- django/utils/cache.py       (revision 16543)
4+++ django/utils/cache.py       (working copy)
5@@ -66,6 +66,12 @@
6     if 'max-age' in cc and 'max_age' in kwargs:
7         kwargs['max_age'] = min(cc['max-age'], kwargs['max_age'])
8 
9+    # Allow overriding private caching and vice versa
10+    if 'private' in cc and 'public' in kwargs:
11+        del cc['private']
12+    elif 'public' in cc and 'private' in kwargs:
13+        del cc['public']
14+
15     for (k, v) in kwargs.items():
16         cc[k.replace('_', '-')] = v
17     cc = ', '.join([dictvalue(el) for el in cc.items()])
18Index: docs/topics/cache.txt
19===================================================================
20--- docs/topics/cache.txt       (revision 16543)
21+++ docs/topics/cache.txt       (working copy)
22@@ -1059,6 +1059,28 @@
23 This decorator takes care of sending out the appropriate HTTP header behind the
24 scenes.
25 
26+Note that the cache control settings "private" and "public" are mutually
27+exclusive. The decorator ensures that the "public" directive is removed if
28+"private" should be set (and vice versa). An example use of the two directives
29+would be a blog site that offers both private and public entries. Public
30+entries may be cached on any shared cache. The following code uses
31+``patch_cache_control``, the manual way to modify the cache control header
32+(it is internally called by the ``cache_control`` decorator)::
33+
34+    from django.views.decorators.cache import patch_cache_control
35+    from django.views.decorators.vary import vary_on_cookie
36+
37+    @vary_on_cookie
38+    def list_blog_entries_view(request):
39+        if request.user.is_anonymous():
40+            response = render_only_public_entries()
41+            patch_cache_control(response, public=True)
42+        else:
43+            response = render_private_and_public_entries(request.user)
44+            patch_cache_control(response, private=True)
45+
46+        return response
47+
48 There are a few other ways to control cache parameters. For example, HTTP
49 allows applications to do the following:
50 
51Index: tests/regressiontests/cache/tests.py
52===================================================================
53--- tests/regressiontests/cache/tests.py        (revision 16543)
54+++ tests/regressiontests/cache/tests.py        (working copy)
55@@ -5,6 +5,7 @@
56 
57 import hashlib
58 import os
59+import re
60 import tempfile
61 import time
62 import warnings
63@@ -19,7 +20,7 @@
64 from django.test.utils import get_warnings_state, restore_warnings_state
65 from django.utils import translation
66 from django.utils import unittest
67-from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
68+from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key, patch_cache_control
69 from django.views.decorators.cache import cache_page
70 
71 from regressiontests.cache.models import Poll, expensive_calculation
72@@ -998,6 +999,34 @@
73         learn_cache_key(request, response)
74         self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.HEAD.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
75 
76+    def test_patch_cache_control(self):
77+        tests = (
78+            # Initial Cache-Control, kwargs to patch_cache_control, expected Cache-Control parts
79+            (None, {'private' : True}, set(['private'])),
80+
81+            # Test whether private/public attributes are mutually exclusive
82+            ('private', {'private' : True}, set(['private'])),
83+            ('private', {'public' : True}, set(['public'])),
84+            ('public', {'private' : True}, set(['private'])),
85+            ('must-revalidate,max-age=60,private', {'public' : True}, set(['must-revalidate', 'max-age=60', 'public'])),
86+            ('must-revalidate,max-age=60,public', {'private' : True}, set(['must-revalidate', 'max-age=60', 'private'])),
87+
88+            ('public', {'public' : True}, set(['public'])),
89+            ('private', {'private' : True}, set(['private'])),
90+
91+            ('must-revalidate,max-age=60', {'public' : True}, set(['must-revalidate', 'max-age=60', 'public'])),
92+        )
93+
94+        cc_delim_re = re.compile(r'\s*,\s*')
95+
96+        for initial_cc, newheaders, expected_cc in tests:
97+            response = HttpResponse()
98+            if initial_cc is not None:
99+                response['Cache-Control'] = initial_cc
100+            patch_cache_control(response, **newheaders)
101+            parts = set(cc_delim_re.split(response['Cache-Control']))
102+            self.assertEqual(parts, expected_cc)
103+
104 class PrefixedCacheUtils(CacheUtils):
105     def setUp(self):
106         super(PrefixedCacheUtils, self).setUp()