Author: jezdez
Date: 2011-09-08 06:25:31 -0700 (Thu, 08 Sep 2011)
New Revision: 16729
Modified:
django/trunk/django/utils/cache.py
django/trunk/tests/regressiontests/cache/tests.py
Log:
Fixed #16003 -- Restored compatibility of the admin when using USE_ETAGS.
Thanks for the initial patch, pterk.
Modified: django/trunk/django/utils/cache.py
===================================================================
--- django/trunk/django/utils/cache.py 2011-09-08 13:25:24 UTC (rev 16728)
+++ django/trunk/django/utils/cache.py 2011-09-08 13:25:31 UTC (rev 16729)
@@ -92,6 +92,10 @@
except (ValueError, TypeError):
pass
+def _set_response_etag(response):
+ response['ETag'] = '"%s"' % hashlib.md5(response.content).hexdigest()
+ return response
+
def patch_response_headers(response, cache_timeout=None):
"""
Adds some useful headers to the given HttpResponse object:
@@ -107,7 +111,10 @@
if cache_timeout < 0:
cache_timeout = 0 # Can't have max-age negative
if settings.USE_ETAGS and not response.has_header('ETag'):
- response['ETag'] = '"%s"' % hashlib.md5(response.content).hexdigest()
+ if hasattr(response, 'render') and callable(response.render):
+ response.add_post_render_callback(_set_response_etag)
+ else:
+ response = _set_response_etag(response)
if not response.has_header('Last-Modified'):
response['Last-Modified'] = http_date()
if not response.has_header('Expires'):
Modified: django/trunk/tests/regressiontests/cache/tests.py
===================================================================
--- django/trunk/tests/regressiontests/cache/tests.py 2011-09-08 13:25:24 UTC
(rev 16728)
+++ django/trunk/tests/regressiontests/cache/tests.py 2011-09-08 13:25:31 UTC
(rev 16729)
@@ -2,6 +2,7 @@
# Unit tests for cache framework
# Uses whatever cache backend is set in the test settings file.
+from __future__ import with_statement
import hashlib
import os
@@ -13,14 +14,19 @@
from django.conf import settings
from django.core import management
from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS
-from django.core.cache.backends.base import CacheKeyWarning,
InvalidCacheBackendError
+from django.core.cache.backends.base import (CacheKeyWarning,
+ InvalidCacheBackendError)
from django.http import HttpResponse, HttpRequest, QueryDict
-from django.middleware.cache import FetchFromCacheMiddleware,
UpdateCacheMiddleware, CacheMiddleware
-from django.test import RequestFactory
-from django.test.utils import get_warnings_state, restore_warnings_state
-from django.utils import translation
-from django.utils import unittest
-from django.utils.cache import patch_vary_headers, get_cache_key,
learn_cache_key, patch_cache_control
+from django.middleware.cache import (FetchFromCacheMiddleware,
+ UpdateCacheMiddleware, CacheMiddleware)
+from django.template import Template
+from django.template.response import TemplateResponse
+from django.test import TestCase, RequestFactory
+from django.test.utils import (get_warnings_state, restore_warnings_state,
+ override_settings)
+from django.utils import translation, unittest
+from django.utils.cache import (patch_vary_headers, get_cache_key,
+ learn_cache_key, patch_cache_control, patch_response_headers)
from django.views.decorators.cache import cache_page
from regressiontests.cache.models import Poll, expensive_calculation
@@ -1491,5 +1497,110 @@
response = other_with_timeout_view(request, '18')
self.assertEqual(response.content, 'Hello World 18')
+
+class TestWithTemplateResponse(TestCase):
+ """
+ Tests various headers w/ TemplateResponse.
+
+ Most are probably redundant since they manipulate the same object
+ anyway but the Etag header is 'special' because it relies on the
+ content being complete (which is not necessarily always the case
+ with a TemplateResponse)
+ """
+ def setUp(self):
+ self.path = '/cache/test/'
+
+ def _get_request(self, path, method='GET'):
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_NAME': 'testserver',
+ 'SERVER_PORT': 80,
+ }
+ request.method = method
+ request.path = request.path_info = "/cache/%s" % path
+ return request
+
+ def test_patch_vary_headers(self):
+ headers = (
+ # Initial vary, new headers, resulting vary.
+ (None, ('Accept-Encoding',), 'Accept-Encoding'),
+ ('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
+ ('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
+ ('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
+ ('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie,
Accept-Encoding'),
+ ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'),
'Cookie, Accept-Encoding'),
+ (None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
+ ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'),
'Cookie, Accept-Encoding'),
+ ('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'),
'Cookie, Accept-Encoding'),
+ )
+ for initial_vary, newheaders, resulting_vary in headers:
+ response = TemplateResponse(HttpResponse(), Template("This is a
test"))
+ if initial_vary is not None:
+ response['Vary'] = initial_vary
+ patch_vary_headers(response, newheaders)
+ self.assertEqual(response['Vary'], resulting_vary)
+
+ def test_get_cache_key(self):
+ request = self._get_request(self.path)
+ response = TemplateResponse(HttpResponse(), Template("This is a test"))
+ key_prefix = 'localprefix'
+ # Expect None if no headers have been set yet.
+ self.assertEqual(get_cache_key(request), None)
+ # Set headers to an empty list.
+ learn_cache_key(request, response)
+ self.assertEqual(get_cache_key(request),
'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
+ # Verify that a specified key_prefix is taken into account.
+ learn_cache_key(request, response, key_prefix=key_prefix)
+ self.assertEqual(get_cache_key(request, key_prefix=key_prefix),
'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
+
+ def test_get_cache_key_with_query(self):
+ request = self._get_request(self.path + '?test=1')
+ response = TemplateResponse(HttpResponse(), Template("This is a test"))
+ # Expect None if no headers have been set yet.
+ self.assertEqual(get_cache_key(request), None)
+ # Set headers to an empty list.
+ learn_cache_key(request, response)
+ # Verify that the querystring is taken into account.
+ self.assertEqual(get_cache_key(request),
'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
+
+ @override_settings(USE_ETAGS=False)
+ def test_without_etag(self):
+ response = TemplateResponse(HttpResponse(), Template("This is a test"))
+ self.assertFalse(response.has_header('ETag'))
+ patch_response_headers(response)
+ self.assertFalse(response.has_header('ETag'))
+ response = response.render()
+ self.assertFalse(response.has_header('ETag'))
+
+ @override_settings(USE_ETAGS=True)
+ def test_with_etag(self):
+ response = TemplateResponse(HttpResponse(), Template("This is a test"))
+ self.assertFalse(response.has_header('ETag'))
+ patch_response_headers(response)
+ self.assertFalse(response.has_header('ETag'))
+ response = response.render()
+ self.assertTrue(response.has_header('ETag'))
+
+TestWithTemplateResponse = override_settings(
+ CACHE_MIDDLEWARE_KEY_PREFIX='settingsprefix',
+ CACHE_MIDDLEWARE_SECONDS=1,
+ USE_I18N=False,
+)(TestWithTemplateResponse)
+
+
+class TestEtagWithAdmin(TestCase):
+ # See https://code.djangoproject.com/ticket/16003
+ def test_admin(self):
+ with self.settings(USE_ETAGS=False):
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
+ self.assertFalse(response.has_header('ETag'))
+
+ with self.settings(USE_ETAGS=True):
+ response = self.client.get('/test_admin/admin/')
+ self.assertEqual(response.status_code, 200)
+ self.assertTrue(response.has_header('ETag'))
+
if __name__ == '__main__':
unittest.main()
+
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.