Loading django/utils/cache.py +7 −4 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import time from django.conf import settings from django.core.cache import get_cache from django.utils.encoding import smart_str, iri_to_uri from django.utils.encoding import smart_str, iri_to_uri, force_unicode from django.utils.http import http_date from django.utils.timezone import get_current_timezone_name from django.utils.translation import get_language Loading Loading @@ -165,9 +165,12 @@ def _i18n_cache_key_suffix(request, cache_key): # which in turn can also fall back to settings.LANGUAGE_CODE cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language()) if settings.USE_TZ: # Windows uses non-standard timezone names that may include spaces, # which triggers CacheKeyWarning. cache_key += '.%s' % get_current_timezone_name().replace(' ', '_') # The datetime module doesn't restrict the output of tzname(). # Windows is known to use non-standard, locale-dependant names. # User-defined tzinfo classes may return absolutely anything. # Hence this paranoid conversion to create a valid cache key. tz_name = force_unicode(get_current_timezone_name(), errors='ignore') cache_key += '.%s' % tz_name.encode('ascii', 'ignore').replace(' ', '_') return cache_key def _generate_cache_key(request, method, headerlist, key_prefix): Loading tests/regressiontests/cache/tests.py +29 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ from django.test.utils import (get_warnings_state, restore_warnings_state, from django.utils import timezone, translation, unittest from django.utils.cache import (patch_vary_headers, get_cache_key, learn_cache_key, patch_cache_control, patch_response_headers) from django.utils.encoding import force_unicode from django.views.decorators.cache import cache_page from .models import Poll, expensive_calculation Loading Loading @@ -1270,7 +1271,10 @@ class CacheI18nTest(TestCase): @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) def test_cache_key_i18n_timezone(self): request = self._get_request() tz = timezone.get_current_timezone_name().replace(' ', '_') # This is tightly coupled to the implementation, # but it's the most straightforward way to test the key. tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore') tz = tz.encode('ascii', 'ignore').replace(' ', '_') response = HttpResponse() key = learn_cache_key(request, response) self.assertIn(tz, key, "Cache keys should include the time zone name when time zones are active") Loading @@ -1281,12 +1285,35 @@ class CacheI18nTest(TestCase): def test_cache_key_no_i18n (self): request = self._get_request() lang = translation.get_language() tz = timezone.get_current_timezone_name().replace(' ', '_') tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore') tz = tz.encode('ascii', 'ignore').replace(' ', '_') response = HttpResponse() key = learn_cache_key(request, response) self.assertNotIn(lang, key, "Cache keys shouldn't include the language name when i18n isn't active") self.assertNotIn(tz, key, "Cache keys shouldn't include the time zone name when i18n isn't active") @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) def test_cache_key_with_non_ascii_tzname(self): # Regression test for #17476 class CustomTzName(timezone.UTC): name = '' def tzname(self, dt): return self.name request = self._get_request() response = HttpResponse() with timezone.override(CustomTzName()): CustomTzName.name = 'Hora estándar de Argentina' # UTF-8 string sanitized_name = 'Hora_estndar_de_Argentina' self.assertIn(sanitized_name, learn_cache_key(request, response), "Cache keys should include the time zone name when time zones are active") CustomTzName.name = u'Hora estándar de Argentina' # unicode sanitized_name = 'Hora_estndar_de_Argentina' self.assertIn(sanitized_name, learn_cache_key(request, response), "Cache keys should include the time zone name when time zones are active") @override_settings( CACHE_MIDDLEWARE_KEY_PREFIX="test", CACHE_MIDDLEWARE_SECONDS=60, Loading Loading
django/utils/cache.py +7 −4 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ import time from django.conf import settings from django.core.cache import get_cache from django.utils.encoding import smart_str, iri_to_uri from django.utils.encoding import smart_str, iri_to_uri, force_unicode from django.utils.http import http_date from django.utils.timezone import get_current_timezone_name from django.utils.translation import get_language Loading Loading @@ -165,9 +165,12 @@ def _i18n_cache_key_suffix(request, cache_key): # which in turn can also fall back to settings.LANGUAGE_CODE cache_key += '.%s' % getattr(request, 'LANGUAGE_CODE', get_language()) if settings.USE_TZ: # Windows uses non-standard timezone names that may include spaces, # which triggers CacheKeyWarning. cache_key += '.%s' % get_current_timezone_name().replace(' ', '_') # The datetime module doesn't restrict the output of tzname(). # Windows is known to use non-standard, locale-dependant names. # User-defined tzinfo classes may return absolutely anything. # Hence this paranoid conversion to create a valid cache key. tz_name = force_unicode(get_current_timezone_name(), errors='ignore') cache_key += '.%s' % tz_name.encode('ascii', 'ignore').replace(' ', '_') return cache_key def _generate_cache_key(request, method, headerlist, key_prefix): Loading
tests/regressiontests/cache/tests.py +29 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ from django.test.utils import (get_warnings_state, restore_warnings_state, from django.utils import timezone, translation, unittest from django.utils.cache import (patch_vary_headers, get_cache_key, learn_cache_key, patch_cache_control, patch_response_headers) from django.utils.encoding import force_unicode from django.views.decorators.cache import cache_page from .models import Poll, expensive_calculation Loading Loading @@ -1270,7 +1271,10 @@ class CacheI18nTest(TestCase): @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) def test_cache_key_i18n_timezone(self): request = self._get_request() tz = timezone.get_current_timezone_name().replace(' ', '_') # This is tightly coupled to the implementation, # but it's the most straightforward way to test the key. tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore') tz = tz.encode('ascii', 'ignore').replace(' ', '_') response = HttpResponse() key = learn_cache_key(request, response) self.assertIn(tz, key, "Cache keys should include the time zone name when time zones are active") Loading @@ -1281,12 +1285,35 @@ class CacheI18nTest(TestCase): def test_cache_key_no_i18n (self): request = self._get_request() lang = translation.get_language() tz = timezone.get_current_timezone_name().replace(' ', '_') tz = force_unicode(timezone.get_current_timezone_name(), errors='ignore') tz = tz.encode('ascii', 'ignore').replace(' ', '_') response = HttpResponse() key = learn_cache_key(request, response) self.assertNotIn(lang, key, "Cache keys shouldn't include the language name when i18n isn't active") self.assertNotIn(tz, key, "Cache keys shouldn't include the time zone name when i18n isn't active") @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) def test_cache_key_with_non_ascii_tzname(self): # Regression test for #17476 class CustomTzName(timezone.UTC): name = '' def tzname(self, dt): return self.name request = self._get_request() response = HttpResponse() with timezone.override(CustomTzName()): CustomTzName.name = 'Hora estándar de Argentina' # UTF-8 string sanitized_name = 'Hora_estndar_de_Argentina' self.assertIn(sanitized_name, learn_cache_key(request, response), "Cache keys should include the time zone name when time zones are active") CustomTzName.name = u'Hora estándar de Argentina' # unicode sanitized_name = 'Hora_estndar_de_Argentina' self.assertIn(sanitized_name, learn_cache_key(request, response), "Cache keys should include the time zone name when time zones are active") @override_settings( CACHE_MIDDLEWARE_KEY_PREFIX="test", CACHE_MIDDLEWARE_SECONDS=60, Loading