| 1 | diff --git a/django/middleware/cache.py b/django/middleware/cache.py
|
|---|
| 2 | index 34bf0ca..049238e 100644
|
|---|
| 3 | --- a/django/middleware/cache.py
|
|---|
| 4 | +++ b/django/middleware/cache.py
|
|---|
| 5 | @@ -48,12 +48,72 @@ More details about how the caching works:
|
|---|
| 6 |
|
|---|
| 7 | """
|
|---|
| 8 |
|
|---|
| 9 | +import hashlib
|
|---|
| 10 | +
|
|---|
| 11 | +from django.utils.encoding import iri_to_uri
|
|---|
| 12 | from django.conf import settings
|
|---|
| 13 | from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS
|
|---|
| 14 | -from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
|
|---|
| 15 | +from django.utils.cache import patch_response_headers, get_max_age, cc_delim_re
|
|---|
| 16 | +from django.utils.timezone import get_current_timezone_name
|
|---|
| 17 | +from django.utils.translation import get_language
|
|---|
| 18 |
|
|---|
| 19 | +class TwoPartCacheMiddlewareBase(object):
|
|---|
| 20 | + @classmethod
|
|---|
| 21 | + def get_cache_key(cls, request, key_prefix=None, method='GET', cache=None):
|
|---|
| 22 | + """
|
|---|
| 23 | + Returns a cache key based on the request path and query. It can be used
|
|---|
| 24 | + in the request phase because it pulls the list of headers to take into
|
|---|
| 25 | + account from the global path registry and uses those to build a cache key
|
|---|
| 26 | + to check against.
|
|---|
| 27 |
|
|---|
| 28 | -class UpdateCacheMiddleware(object):
|
|---|
| 29 | + If there is no headerlist stored, the page needs to be rebuilt, so this
|
|---|
| 30 | + function returns None.
|
|---|
| 31 | + """
|
|---|
| 32 | + if key_prefix is None:
|
|---|
| 33 | + key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
|---|
| 34 | + cache_key = cls._generate_cache_header_key(key_prefix, request)
|
|---|
| 35 | + if cache is None:
|
|---|
| 36 | + cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
|
|---|
| 37 | + headerlist = cache.get(cache_key, None)
|
|---|
| 38 | + if headerlist is not None:
|
|---|
| 39 | + return cls._generate_cache_key(request, method, headerlist, key_prefix)
|
|---|
| 40 | + else:
|
|---|
| 41 | + return None
|
|---|
| 42 | +
|
|---|
| 43 | + @classmethod
|
|---|
| 44 | + def _i18n_cache_key_suffix(cls, request, cache_key):
|
|---|
| 45 | + """If necessary, adds the current locale or time zone to the cache key."""
|
|---|
| 46 | + if settings.USE_I18N or settings.USE_L10N:
|
|---|
| 47 | + # first check if LocaleMiddleware or another middleware added
|
|---|
| 48 | + # LANGUAGE_CODE to request, then fall back to the active language
|
|---|
| 49 | + # which in turn can also fall back to settings.LANGUAGE_CODE
|
|---|
| 50 | + cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
|
|---|
| 51 | + if settings.USE_TZ:
|
|---|
| 52 | + cache_key += '.%s' % get_current_timezone_name()
|
|---|
| 53 | + return cache_key
|
|---|
| 54 | +
|
|---|
| 55 | + @classmethod
|
|---|
| 56 | + def _generate_cache_key(cls, request, method, headerlist, key_prefix):
|
|---|
| 57 | + """Returns a cache key from the headers given in the header list."""
|
|---|
| 58 | + ctx = hashlib.md5()
|
|---|
| 59 | + for header in headerlist:
|
|---|
| 60 | + value = request.META.get(header, None)
|
|---|
| 61 | + if value is not None:
|
|---|
| 62 | + ctx.update(value)
|
|---|
| 63 | + path = hashlib.md5(iri_to_uri(request.get_full_path()))
|
|---|
| 64 | + cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
|
|---|
| 65 | + key_prefix, method, path.hexdigest(), ctx.hexdigest())
|
|---|
| 66 | + return cls._i18n_cache_key_suffix(request, cache_key)
|
|---|
| 67 | +
|
|---|
| 68 | + @classmethod
|
|---|
| 69 | + def _generate_cache_header_key(cls, key_prefix, request):
|
|---|
| 70 | + """Returns a cache key for the header cache."""
|
|---|
| 71 | + path = hashlib.md5(iri_to_uri(request.get_full_path()))
|
|---|
| 72 | + cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
|---|
| 73 | + key_prefix, path.hexdigest())
|
|---|
| 74 | + return cls._i18n_cache_key_suffix(request, cache_key)
|
|---|
| 75 | +
|
|---|
| 76 | +class UpdateCacheMiddleware(TwoPartCacheMiddlewareBase):
|
|---|
| 77 | """
|
|---|
| 78 | Response-phase cache middleware that updates the cache if the response is
|
|---|
| 79 | cacheable.
|
|---|
| 80 | @@ -88,6 +148,38 @@ class UpdateCacheMiddleware(object):
|
|---|
| 81 | return False
|
|---|
| 82 | return True
|
|---|
| 83 |
|
|---|
| 84 | + @classmethod
|
|---|
| 85 | + def learn_cache_key(cls, request, response, cache_timeout=None, key_prefix=None, cache=None):
|
|---|
| 86 | + """
|
|---|
| 87 | + Learns what headers to take into account for some request path from the
|
|---|
| 88 | + response object. It stores those headers in a global path registry so that
|
|---|
| 89 | + later access to that path will know what headers to take into account
|
|---|
| 90 | + without building the response object itself. The headers are named in the
|
|---|
| 91 | + Vary header of the response, but we want to prevent response generation.
|
|---|
| 92 | +
|
|---|
| 93 | + The list of headers to use for cache key generation is stored in the same
|
|---|
| 94 | + cache as the pages themselves. If the cache ages some data out of the
|
|---|
| 95 | + cache, this just means that we have to build the response once to get at
|
|---|
| 96 | + the Vary header and so at the list of headers to use for the cache key.
|
|---|
| 97 | + """
|
|---|
| 98 | + if key_prefix is None:
|
|---|
| 99 | + key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
|---|
| 100 | + if cache_timeout is None:
|
|---|
| 101 | + cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
|---|
| 102 | + cache_key = cls._generate_cache_header_key(key_prefix, request)
|
|---|
| 103 | + if cache is None:
|
|---|
| 104 | + cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
|
|---|
| 105 | + if response.has_header('Vary'):
|
|---|
| 106 | + headerlist = ['HTTP_'+header.upper().replace('-', '_')
|
|---|
| 107 | + for header in cc_delim_re.split(response['Vary'])]
|
|---|
| 108 | + cache.set(cache_key, headerlist, cache_timeout)
|
|---|
| 109 | + return cls._generate_cache_key(request, request.method, headerlist, key_prefix)
|
|---|
| 110 | + else:
|
|---|
| 111 | + # if there is no Vary header, we still need a cache key
|
|---|
| 112 | + # for the request.get_full_path()
|
|---|
| 113 | + cache.set(cache_key, [], cache_timeout)
|
|---|
| 114 | + return cls._generate_cache_key(request, request.method, [], key_prefix)
|
|---|
| 115 | +
|
|---|
| 116 | def process_response(self, request, response):
|
|---|
| 117 | """Sets the cache, if needed."""
|
|---|
| 118 | if not self._should_update_cache(request, response):
|
|---|
| 119 | @@ -106,7 +198,7 @@ class UpdateCacheMiddleware(object):
|
|---|
| 120 | return response
|
|---|
| 121 | patch_response_headers(response, timeout)
|
|---|
| 122 | if timeout:
|
|---|
| 123 | - cache_key = learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache)
|
|---|
| 124 | + cache_key = self.learn_cache_key(request, response, timeout, self.key_prefix, cache=self.cache)
|
|---|
| 125 | if hasattr(response, 'render') and callable(response.render):
|
|---|
| 126 | response.add_post_render_callback(
|
|---|
| 127 | lambda r: self.cache.set(cache_key, r, timeout)
|
|---|
| 128 | @@ -115,7 +207,7 @@ class UpdateCacheMiddleware(object):
|
|---|
| 129 | self.cache.set(cache_key, response, timeout)
|
|---|
| 130 | return response
|
|---|
| 131 |
|
|---|
| 132 | -class FetchFromCacheMiddleware(object):
|
|---|
| 133 | +class FetchFromCacheMiddleware(TwoPartCacheMiddlewareBase):
|
|---|
| 134 | """
|
|---|
| 135 | Request-phase cache middleware that fetches a page from the cache.
|
|---|
| 136 |
|
|---|
| 137 | @@ -140,14 +232,14 @@ class FetchFromCacheMiddleware(object):
|
|---|
| 138 | return None # Don't bother checking the cache.
|
|---|
| 139 |
|
|---|
| 140 | # try and get the cached GET response
|
|---|
| 141 | - cache_key = get_cache_key(request, self.key_prefix, 'GET', cache=self.cache)
|
|---|
| 142 | + cache_key = self.get_cache_key(request, self.key_prefix, 'GET', cache=self.cache)
|
|---|
| 143 | if cache_key is None:
|
|---|
| 144 | request._cache_update_cache = True
|
|---|
| 145 | return None # No cache information available, need to rebuild.
|
|---|
| 146 | response = self.cache.get(cache_key, None)
|
|---|
| 147 | # if it wasn't found and we are looking for a HEAD, try looking just for that
|
|---|
| 148 | if response is None and request.method == 'HEAD':
|
|---|
| 149 | - cache_key = get_cache_key(request, self.key_prefix, 'HEAD', cache=self.cache)
|
|---|
| 150 | + cache_key = self.get_cache_key(request, self.key_prefix, 'HEAD', cache=self.cache)
|
|---|
| 151 | response = self.cache.get(cache_key, None)
|
|---|
| 152 |
|
|---|
| 153 | if response is None:
|
|---|
| 154 | diff --git a/django/utils/cache.py b/django/utils/cache.py
|
|---|
| 155 | index 1015c2f..9448aae 100644
|
|---|
| 156 | --- a/django/utils/cache.py
|
|---|
| 157 | +++ b/django/utils/cache.py
|
|---|
| 158 | @@ -23,10 +23,8 @@ import time
|
|---|
| 159 |
|
|---|
| 160 | from django.conf import settings
|
|---|
| 161 | from django.core.cache import get_cache
|
|---|
| 162 | -from django.utils.encoding import smart_str, iri_to_uri
|
|---|
| 163 | +from django.utils.encoding import smart_str
|
|---|
| 164 | from django.utils.http import http_date
|
|---|
| 165 | -from django.utils.timezone import get_current_timezone_name
|
|---|
| 166 | -from django.utils.translation import get_language
|
|---|
| 167 |
|
|---|
| 168 | cc_delim_re = re.compile(r'\s*,\s*')
|
|---|
| 169 |
|
|---|
| 170 | @@ -122,12 +120,6 @@ def patch_response_headers(response, cache_timeout=None):
|
|---|
| 171 | response['Expires'] = http_date(time.time() + cache_timeout)
|
|---|
| 172 | patch_cache_control(response, max_age=cache_timeout)
|
|---|
| 173 |
|
|---|
| 174 | -def add_never_cache_headers(response):
|
|---|
| 175 | - """
|
|---|
| 176 | - Adds headers to a response to indicate that a page should never be cached.
|
|---|
| 177 | - """
|
|---|
| 178 | - patch_response_headers(response, cache_timeout=-1)
|
|---|
| 179 | -
|
|---|
| 180 | def patch_vary_headers(response, newheaders):
|
|---|
| 181 | """
|
|---|
| 182 | Adds (or updates) the "Vary" header in the given HttpResponse object.
|
|---|
| 183 | @@ -157,88 +149,6 @@ def has_vary_header(response, header_query):
|
|---|
| 184 | existing_headers = set([header.lower() for header in vary_headers])
|
|---|
| 185 | return header_query.lower() in existing_headers
|
|---|
| 186 |
|
|---|
| 187 | -def _i18n_cache_key_suffix(request, cache_key):
|
|---|
| 188 | - """If necessary, adds the current locale or time zone to the cache key."""
|
|---|
| 189 | - if settings.USE_I18N or settings.USE_L10N:
|
|---|
| 190 | - # first check if LocaleMiddleware or another middleware added
|
|---|
| 191 | - # LANGUAGE_CODE to request, then fall back to the active language
|
|---|
| 192 | - # which in turn can also fall back to settings.LANGUAGE_CODE
|
|---|
| 193 | - cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language())
|
|---|
| 194 | - if settings.USE_TZ:
|
|---|
| 195 | - cache_key += '.%s' % get_current_timezone_name()
|
|---|
| 196 | - return cache_key
|
|---|
| 197 | -
|
|---|
| 198 | -def _generate_cache_key(request, method, headerlist, key_prefix):
|
|---|
| 199 | - """Returns a cache key from the headers given in the header list."""
|
|---|
| 200 | - ctx = hashlib.md5()
|
|---|
| 201 | - for header in headerlist:
|
|---|
| 202 | - value = request.META.get(header, None)
|
|---|
| 203 | - if value is not None:
|
|---|
| 204 | - ctx.update(value)
|
|---|
| 205 | - path = hashlib.md5(iri_to_uri(request.get_full_path()))
|
|---|
| 206 | - cache_key = 'views.decorators.cache.cache_page.%s.%s.%s.%s' % (
|
|---|
| 207 | - key_prefix, method, path.hexdigest(), ctx.hexdigest())
|
|---|
| 208 | - return _i18n_cache_key_suffix(request, cache_key)
|
|---|
| 209 | -
|
|---|
| 210 | -def _generate_cache_header_key(key_prefix, request):
|
|---|
| 211 | - """Returns a cache key for the header cache."""
|
|---|
| 212 | - path = hashlib.md5(iri_to_uri(request.get_full_path()))
|
|---|
| 213 | - cache_key = 'views.decorators.cache.cache_header.%s.%s' % (
|
|---|
| 214 | - key_prefix, path.hexdigest())
|
|---|
| 215 | - return _i18n_cache_key_suffix(request, cache_key)
|
|---|
| 216 | -
|
|---|
| 217 | -def get_cache_key(request, key_prefix=None, method='GET', cache=None):
|
|---|
| 218 | - """
|
|---|
| 219 | - Returns a cache key based on the request path and query. It can be used
|
|---|
| 220 | - in the request phase because it pulls the list of headers to take into
|
|---|
| 221 | - account from the global path registry and uses those to build a cache key
|
|---|
| 222 | - to check against.
|
|---|
| 223 | -
|
|---|
| 224 | - If there is no headerlist stored, the page needs to be rebuilt, so this
|
|---|
| 225 | - function returns None.
|
|---|
| 226 | - """
|
|---|
| 227 | - if key_prefix is None:
|
|---|
| 228 | - key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
|---|
| 229 | - cache_key = _generate_cache_header_key(key_prefix, request)
|
|---|
| 230 | - if cache is None:
|
|---|
| 231 | - cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
|
|---|
| 232 | - headerlist = cache.get(cache_key, None)
|
|---|
| 233 | - if headerlist is not None:
|
|---|
| 234 | - return _generate_cache_key(request, method, headerlist, key_prefix)
|
|---|
| 235 | - else:
|
|---|
| 236 | - return None
|
|---|
| 237 | -
|
|---|
| 238 | -def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cache=None):
|
|---|
| 239 | - """
|
|---|
| 240 | - Learns what headers to take into account for some request path from the
|
|---|
| 241 | - response object. It stores those headers in a global path registry so that
|
|---|
| 242 | - later access to that path will know what headers to take into account
|
|---|
| 243 | - without building the response object itself. The headers are named in the
|
|---|
| 244 | - Vary header of the response, but we want to prevent response generation.
|
|---|
| 245 | -
|
|---|
| 246 | - The list of headers to use for cache key generation is stored in the same
|
|---|
| 247 | - cache as the pages themselves. If the cache ages some data out of the
|
|---|
| 248 | - cache, this just means that we have to build the response once to get at
|
|---|
| 249 | - the Vary header and so at the list of headers to use for the cache key.
|
|---|
| 250 | - """
|
|---|
| 251 | - if key_prefix is None:
|
|---|
| 252 | - key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
|
|---|
| 253 | - if cache_timeout is None:
|
|---|
| 254 | - cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
|
|---|
| 255 | - cache_key = _generate_cache_header_key(key_prefix, request)
|
|---|
| 256 | - if cache is None:
|
|---|
| 257 | - cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
|
|---|
| 258 | - if response.has_header('Vary'):
|
|---|
| 259 | - headerlist = ['HTTP_'+header.upper().replace('-', '_')
|
|---|
| 260 | - for header in cc_delim_re.split(response['Vary'])]
|
|---|
| 261 | - cache.set(cache_key, headerlist, cache_timeout)
|
|---|
| 262 | - return _generate_cache_key(request, request.method, headerlist, key_prefix)
|
|---|
| 263 | - else:
|
|---|
| 264 | - # if there is no Vary header, we still need a cache key
|
|---|
| 265 | - # for the request.get_full_path()
|
|---|
| 266 | - cache.set(cache_key, [], cache_timeout)
|
|---|
| 267 | - return _generate_cache_key(request, request.method, [], key_prefix)
|
|---|
| 268 | -
|
|---|
| 269 |
|
|---|
| 270 | def _to_tuple(s):
|
|---|
| 271 | t = s.split('=',1)
|
|---|
| 272 | diff --git a/django/views/decorators/cache.py b/django/views/decorators/cache.py
|
|---|
| 273 | index a39cc54..2847e05 100644
|
|---|
| 274 | --- a/django/views/decorators/cache.py
|
|---|
| 275 | +++ b/django/views/decorators/cache.py
|
|---|
| 276 | @@ -1,6 +1,6 @@
|
|---|
| 277 | from functools import wraps
|
|---|
| 278 | from django.utils.decorators import decorator_from_middleware_with_args, available_attrs
|
|---|
| 279 | -from django.utils.cache import patch_cache_control, add_never_cache_headers
|
|---|
| 280 | +from django.utils.cache import patch_cache_control, patch_response_headers
|
|---|
| 281 | from django.middleware.cache import CacheMiddleware
|
|---|
| 282 |
|
|---|
| 283 |
|
|---|
| 284 | @@ -86,6 +86,6 @@ def never_cache(view_func):
|
|---|
| 285 | @wraps(view_func, assigned=available_attrs(view_func))
|
|---|
| 286 | def _wrapped_view_func(request, *args, **kwargs):
|
|---|
| 287 | response = view_func(request, *args, **kwargs)
|
|---|
| 288 | - add_never_cache_headers(response)
|
|---|
| 289 | + patch_response_headers(response, cache_timeout=0)
|
|---|
| 290 | return response
|
|---|
| 291 | return _wrapped_view_func
|
|---|
| 292 | diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
|
|---|
| 293 | index 307588c..ea13421 100644
|
|---|
| 294 | --- a/tests/regressiontests/cache/tests.py
|
|---|
| 295 | +++ b/tests/regressiontests/cache/tests.py
|
|---|
| 296 | @@ -19,15 +19,15 @@ from django.core.cache.backends.base import (CacheKeyWarning,
|
|---|
| 297 | from django.db import router
|
|---|
| 298 | from django.http import HttpResponse, HttpRequest, QueryDict
|
|---|
| 299 | from django.middleware.cache import (FetchFromCacheMiddleware,
|
|---|
| 300 | - UpdateCacheMiddleware, CacheMiddleware)
|
|---|
| 301 | + UpdateCacheMiddleware, CacheMiddleware, TwoPartCacheMiddlewareBase)
|
|---|
| 302 | from django.template import Template
|
|---|
| 303 | from django.template.response import TemplateResponse
|
|---|
| 304 | from django.test import TestCase, TransactionTestCase, RequestFactory
|
|---|
| 305 | from django.test.utils import (get_warnings_state, restore_warnings_state,
|
|---|
| 306 | override_settings)
|
|---|
| 307 | from django.utils import timezone, translation, unittest
|
|---|
| 308 | -from django.utils.cache import (patch_vary_headers, get_cache_key,
|
|---|
| 309 | - learn_cache_key, patch_cache_control, patch_response_headers)
|
|---|
| 310 | +from django.utils.cache import (patch_vary_headers,
|
|---|
| 311 | + patch_cache_control, patch_response_headers)
|
|---|
| 312 | from django.views.decorators.cache import cache_page
|
|---|
| 313 |
|
|---|
| 314 | from .models import Poll, expensive_calculation
|
|---|
| 315 | @@ -998,22 +998,11 @@ class CacheUtils(TestCase):
|
|---|
| 316 | """TestCase for django.utils.cache functions."""
|
|---|
| 317 |
|
|---|
| 318 | def setUp(self):
|
|---|
| 319 | - self.path = '/cache/test/'
|
|---|
| 320 | self.cache = get_cache('default')
|
|---|
| 321 |
|
|---|
| 322 | def tearDown(self):
|
|---|
| 323 | self.cache.clear()
|
|---|
| 324 |
|
|---|
| 325 | - def _get_request(self, path, method='GET'):
|
|---|
| 326 | - request = HttpRequest()
|
|---|
| 327 | - request.META = {
|
|---|
| 328 | - 'SERVER_NAME': 'testserver',
|
|---|
| 329 | - 'SERVER_PORT': 80,
|
|---|
| 330 | - }
|
|---|
| 331 | - request.method = method
|
|---|
| 332 | - request.path = request.path_info = "/cache/%s" % path
|
|---|
| 333 | - return request
|
|---|
| 334 | -
|
|---|
| 335 | def test_patch_vary_headers(self):
|
|---|
| 336 | headers = (
|
|---|
| 337 | # Initial vary, new headers, resulting vary.
|
|---|
| 338 | @@ -1034,37 +1023,6 @@ class CacheUtils(TestCase):
|
|---|
| 339 | patch_vary_headers(response, newheaders)
|
|---|
| 340 | self.assertEqual(response['Vary'], resulting_vary)
|
|---|
| 341 |
|
|---|
| 342 | - def test_get_cache_key(self):
|
|---|
| 343 | - request = self._get_request(self.path)
|
|---|
| 344 | - response = HttpResponse()
|
|---|
| 345 | - key_prefix = 'localprefix'
|
|---|
| 346 | - # Expect None if no headers have been set yet.
|
|---|
| 347 | - self.assertEqual(get_cache_key(request), None)
|
|---|
| 348 | - # Set headers to an empty list.
|
|---|
| 349 | - learn_cache_key(request, response)
|
|---|
| 350 | - self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 351 | - # Verify that a specified key_prefix is taken into account.
|
|---|
| 352 | - learn_cache_key(request, response, key_prefix=key_prefix)
|
|---|
| 353 | - self.assertEqual(get_cache_key(request, key_prefix=key_prefix), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 354 | -
|
|---|
| 355 | - def test_get_cache_key_with_query(self):
|
|---|
| 356 | - request = self._get_request(self.path + '?test=1')
|
|---|
| 357 | - response = HttpResponse()
|
|---|
| 358 | - # Expect None if no headers have been set yet.
|
|---|
| 359 | - self.assertEqual(get_cache_key(request), None)
|
|---|
| 360 | - # Set headers to an empty list.
|
|---|
| 361 | - learn_cache_key(request, response)
|
|---|
| 362 | - # Verify that the querystring is taken into account.
|
|---|
| 363 | - self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 364 | -
|
|---|
| 365 | - def test_learn_cache_key(self):
|
|---|
| 366 | - request = self._get_request(self.path, 'HEAD')
|
|---|
| 367 | - response = HttpResponse()
|
|---|
| 368 | - response['Vary'] = 'Pony'
|
|---|
| 369 | - # Make sure that the Vary header is added to the key hash
|
|---|
| 370 | - learn_cache_key(request, response)
|
|---|
| 371 | - self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 372 | -
|
|---|
| 373 | def test_patch_cache_control(self):
|
|---|
| 374 | tests = (
|
|---|
| 375 | # Initial Cache-Control, kwargs to patch_cache_control, expected Cache-Control parts
|
|---|
| 376 | @@ -1342,6 +1300,7 @@ class CacheMiddlewareTest(TestCase):
|
|---|
| 377 |
|
|---|
| 378 | def setUp(self):
|
|---|
| 379 | self.factory = RequestFactory()
|
|---|
| 380 | + self.path = '/cache/test/'
|
|---|
| 381 | self.default_cache = get_cache('default')
|
|---|
| 382 | self.other_cache = get_cache('other')
|
|---|
| 383 |
|
|---|
| 384 | @@ -1381,6 +1340,48 @@ class CacheMiddlewareTest(TestCase):
|
|---|
| 385 | self.assertEqual(as_view_decorator_with_custom.cache_alias, 'other')
|
|---|
| 386 | self.assertEqual(as_view_decorator_with_custom.cache_anonymous_only, True)
|
|---|
| 387 |
|
|---|
| 388 | + def _get_request(self, path, method='GET'):
|
|---|
| 389 | + request = HttpRequest()
|
|---|
| 390 | + request.META = {
|
|---|
| 391 | + 'SERVER_NAME': 'testserver',
|
|---|
| 392 | + 'SERVER_PORT': 80,
|
|---|
| 393 | + }
|
|---|
| 394 | + request.method = method
|
|---|
| 395 | + request.path = request.path_info = "/cache/%s" % path
|
|---|
| 396 | + return request
|
|---|
| 397 | +
|
|---|
| 398 | + def test_get_cache_key(self):
|
|---|
| 399 | + request = self._get_request(self.path)
|
|---|
| 400 | + response = HttpResponse()
|
|---|
| 401 | + key_prefix = 'localprefix'
|
|---|
| 402 | + # Expect None if no headers have been set yet.
|
|---|
| 403 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), None)
|
|---|
| 404 | + # Set headers to an empty list.
|
|---|
| 405 | + UpdateCacheMiddleware.learn_cache_key(request, response)
|
|---|
| 406 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 407 | + # Verify that a specified key_prefix is taken into account.
|
|---|
| 408 | + UpdateCacheMiddleware.learn_cache_key(request, response, key_prefix=key_prefix)
|
|---|
| 409 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request, key_prefix=key_prefix), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 410 | +
|
|---|
| 411 | + def test_get_cache_key_with_query(self):
|
|---|
| 412 | + request = self._get_request(self.path + '?test=1')
|
|---|
| 413 | + response = HttpResponse()
|
|---|
| 414 | + # Expect None if no headers have been set yet.
|
|---|
| 415 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), None)
|
|---|
| 416 | + # Set headers to an empty list.
|
|---|
| 417 | + UpdateCacheMiddleware.learn_cache_key(request, response)
|
|---|
| 418 | + # Verify that the querystring is taken into account.
|
|---|
| 419 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 420 | +
|
|---|
| 421 | + def test_learn_cache_key(self):
|
|---|
| 422 | + request = self._get_request(self.path, 'HEAD')
|
|---|
| 423 | + response = HttpResponse()
|
|---|
| 424 | + response['Vary'] = 'Pony'
|
|---|
| 425 | + # Make sure that the Vary header is added to the key hash
|
|---|
| 426 | + UpdateCacheMiddleware.learn_cache_key(request, response)
|
|---|
| 427 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 428 | +
|
|---|
| 429 | +
|
|---|
| 430 | def test_middleware(self):
|
|---|
| 431 | middleware = CacheMiddleware()
|
|---|
| 432 | prefix_middleware = CacheMiddleware(key_prefix='prefix1')
|
|---|
| 433 | @@ -1624,23 +1625,23 @@ class TestWithTemplateResponse(TestCase):
|
|---|
| 434 | response = TemplateResponse(HttpResponse(), Template("This is a test"))
|
|---|
| 435 | key_prefix = 'localprefix'
|
|---|
| 436 | # Expect None if no headers have been set yet.
|
|---|
| 437 | - self.assertEqual(get_cache_key(request), None)
|
|---|
| 438 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), None)
|
|---|
| 439 | # Set headers to an empty list.
|
|---|
| 440 | - learn_cache_key(request, response)
|
|---|
| 441 | - self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 442 | + UpdateCacheMiddleware.learn_cache_key(request, response)
|
|---|
| 443 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 444 | # Verify that a specified key_prefix is taken into account.
|
|---|
| 445 | - learn_cache_key(request, response, key_prefix=key_prefix)
|
|---|
| 446 | - self.assertEqual(get_cache_key(request, key_prefix=key_prefix), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 447 | + UpdateCacheMiddleware.learn_cache_key(request, response, key_prefix=key_prefix)
|
|---|
| 448 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request, key_prefix=key_prefix), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 449 |
|
|---|
| 450 | def test_get_cache_key_with_query(self):
|
|---|
| 451 | request = self._get_request(self.path + '?test=1')
|
|---|
| 452 | response = TemplateResponse(HttpResponse(), Template("This is a test"))
|
|---|
| 453 | # Expect None if no headers have been set yet.
|
|---|
| 454 | - self.assertEqual(get_cache_key(request), None)
|
|---|
| 455 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), None)
|
|---|
| 456 | # Set headers to an empty list.
|
|---|
| 457 | - learn_cache_key(request, response)
|
|---|
| 458 | + UpdateCacheMiddleware.learn_cache_key(request, response)
|
|---|
| 459 | # Verify that the querystring is taken into account.
|
|---|
| 460 | - self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 461 | + self.assertEqual(TwoPartCacheMiddlewareBase.get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
|
|---|
| 462 |
|
|---|
| 463 | @override_settings(USE_ETAGS=False)
|
|---|
| 464 | def test_without_etag(self):
|
|---|