diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py index 69af9ca297c..ba3b62620db 100644 --- a/django/contrib/staticfiles/storage.py +++ b/django/contrib/staticfiles/storage.py @@ -3,18 +3,13 @@ import json import os import posixpath import re -import warnings from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit from django.conf import settings from django.contrib.staticfiles.utils import check_settings, matches_patterns -from django.core.cache import ( - InvalidCacheBackendError, cache as default_cache, caches, -) from django.core.exceptions import ImproperlyConfigured from django.core.files.base import ContentFile from django.core.files.storage import FileSystemStorage, get_storage_class -from django.utils.deprecation import RemovedInDjango31Warning from django.utils.functional import LazyObject @@ -430,63 +425,6 @@ class ManifestFilesMixin(HashedFilesMixin): return urlunsplit(unparsed_name) -class _MappingCache: - """ - A small dict-like wrapper for a given cache backend instance. - """ - def __init__(self, cache): - self.cache = cache - - def __setitem__(self, key, value): - self.cache.set(key, value) - - def __getitem__(self, key): - value = self.cache.get(key) - if value is None: - raise KeyError("Couldn't find a file name '%s'" % key) - return value - - def clear(self): - self.cache.clear() - - def update(self, data): - self.cache.set_many(data) - - def get(self, key, default=None): - try: - return self[key] - except KeyError: - return default - - -class CachedFilesMixin(HashedFilesMixin): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - try: - self.hashed_files = _MappingCache(caches['staticfiles']) - except InvalidCacheBackendError: - # Use the default backend - self.hashed_files = _MappingCache(default_cache) - - def hash_key(self, name): - key = hashlib.md5(self.clean_name(name).encode()).hexdigest() - return 'staticfiles:%s' % key - - -class CachedStaticFilesStorage(CachedFilesMixin, StaticFilesStorage): - """ - A static file system storage backend which also saves - hashed copies of the files it saves. - """ - def __init__(self, *args, **kwargs): - warnings.warn( - 'CachedStaticFilesStorage is deprecated in favor of ' - 'ManifestStaticFilesStorage.', - RemovedInDjango31Warning, stacklevel=2, - ) - super().__init__(*args, **kwargs) - - class ManifestStaticFilesStorage(ManifestFilesMixin, StaticFilesStorage): """ A static file system storage backend which also saves diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt index 6393e3a7d41..591cba63852 100644 --- a/docs/ref/contrib/staticfiles.txt +++ b/docs/ref/contrib/staticfiles.txt @@ -363,39 +363,6 @@ hashing algorithm. .. _`url()`: https://www.w3.org/TR/CSS2/syndata.html#uri .. _`Cascading Style Sheets`: https://www.w3.org/Style/CSS/ -``CachedStaticFilesStorage`` ----------------------------- - -.. class:: storage.CachedStaticFilesStorage - -.. deprecated:: 2.2 - - ``CachedStaticFilesStorage`` is deprecated as it has some intractable - problems, some of which are outlined below. Use - :class:`~storage.ManifestStaticFilesStorage` or a third-party cloud storage - instead. - -``CachedStaticFilesStorage`` is a similar class like the -:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` class -but uses Django's :doc:`caching framework` for storing the -hashed names of processed files instead of a static manifest file called -``staticfiles.json``. This is mostly useful for situations in which you don't -have access to the file system. - -If you want to override certain options of the cache backend the storage uses, -specify a custom entry in the :setting:`CACHES` setting named -``'staticfiles'``. It falls back to using the ``'default'`` cache backend. - -.. warning:: - - ``CachedStaticFilesStorage`` isn't recommended -- in almost all cases - ``ManifestStaticFilesStorage`` is a better choice. There are several - performance penalties when using ``CachedStaticFilesStorage`` since a cache - miss requires hashing files at runtime. Remote file storage require several - round-trips to hash a file on a cache miss, as several file accesses are - required to ensure that the file hash is correct in the case of nested file - paths. - ``ManifestFilesMixin`` ---------------------- diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index 25ea3947bc8..d90a784fd97 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -238,3 +238,5 @@ to remove usage of these features. ``django.contrib.postgres.forms.FloatRangeField`` are removed. * The ``FILE_CHARSET`` setting is removed. + +* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is removed. diff --git a/tests/staticfiles_tests/test_storage.py b/tests/staticfiles_tests/test_storage.py index 93bd60446a4..afdf4c1761b 100644 --- a/tests/staticfiles_tests/test_storage.py +++ b/tests/staticfiles_tests/test_storage.py @@ -11,10 +11,8 @@ from django.contrib.staticfiles import finders, storage from django.contrib.staticfiles.management.commands.collectstatic import ( Command as CollectstaticCommand, ) -from django.core.cache.backends.base import BaseCache from django.core.management import call_command -from django.test import SimpleTestCase, ignore_warnings, override_settings -from django.utils.deprecation import RemovedInDjango31Warning +from django.test import override_settings from .cases import CollectionTestCase from .settings import TEST_ROOT @@ -231,86 +229,6 @@ class TestHashedFiles: self.assertPostCondition() -@ignore_warnings(category=RemovedInDjango31Warning) -@override_settings( - STATICFILES_STORAGE='django.contrib.staticfiles.storage.CachedStaticFilesStorage', -) -class TestCollectionCachedStorage(TestHashedFiles, CollectionTestCase): - """ - Tests for the Cache busting storage - """ - def test_cache_invalidation(self): - name = "cached/styles.css" - hashed_name = "cached/styles.5e0040571e1a.css" - # check if the cache is filled correctly as expected - cache_key = storage.staticfiles_storage.hash_key(name) - cached_name = storage.staticfiles_storage.hashed_files.get(cache_key) - self.assertEqual(self.hashed_file_path(name), cached_name) - # clearing the cache to make sure we re-set it correctly in the url method - storage.staticfiles_storage.hashed_files.clear() - cached_name = storage.staticfiles_storage.hashed_files.get(cache_key) - self.assertIsNone(cached_name) - self.assertEqual(self.hashed_file_path(name), hashed_name) - cached_name = storage.staticfiles_storage.hashed_files.get(cache_key) - self.assertEqual(cached_name, hashed_name) - - # Check files that had to be hashed multiple times since their content - # includes other files that were hashed. - name = 'cached/relative.css' - hashed_name = 'cached/relative.c3e9e1ea6f2e.css' - cache_key = storage.staticfiles_storage.hash_key(name) - cached_name = storage.staticfiles_storage.hashed_files.get(cache_key) - self.assertIsNone(cached_name) - self.assertEqual(self.hashed_file_path(name), hashed_name) - cached_name = storage.staticfiles_storage.hashed_files.get(cache_key) - self.assertEqual(cached_name, hashed_name) - - def test_cache_key_memcache_validation(self): - """ - Handle cache key creation correctly, see #17861. - """ - name = ( - "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff" - "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff" - "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff" - "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff" - "/some crazy/long filename/ with spaces Here and ?#%#$/other/stuff" - "/some crazy/\x16\xb4" - ) - cache_key = storage.staticfiles_storage.hash_key(name) - cache_validator = BaseCache({}) - cache_validator.validate_key(cache_key) - self.assertEqual(cache_key, 'staticfiles:821ea71ef36f95b3922a77f7364670e7') - - def test_corrupt_intermediate_files(self): - configured_storage = storage.staticfiles_storage - # Clear cache to force rehashing of the files - configured_storage.hashed_files.clear() - # Simulate a corrupt chain of intermediate files by ensuring they don't - # resolve before the max post-process count, which would normally be - # high enough. - configured_storage.max_post_process_passes = 1 - # File without intermediates that can be rehashed without a problem. - self.hashed_file_path('cached/css/img/window.png') - # File with too many intermediates to rehash with the low max - # post-process passes. - err_msg = "The name 'cached/styles.css' could not be hashed with %r." % (configured_storage._wrapped,) - with self.assertRaisesMessage(ValueError, err_msg): - self.hashed_file_path('cached/styles.css') - - -class TestCachedStaticFilesStorageDeprecation(SimpleTestCase): - def test_warning(self): - from django.contrib.staticfiles.storage import CachedStaticFilesStorage - from django.utils.deprecation import RemovedInDjango31Warning - msg = ( - 'CachedStaticFilesStorage is deprecated in favor of ' - 'ManifestStaticFilesStorage.' - ) - with self.assertRaisesMessage(RemovedInDjango31Warning, msg): - CachedStaticFilesStorage() - - @override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.ExtraPatternsStorage') class TestExtraPatternsStorage(CollectionTestCase):