mirror of https://github.com/django/django.git
Refs #28606 -- Removed CachedStaticFilesStorage per deprecation timeline.
This commit is contained in:
parent
81993b47ea
commit
f1894bae30
|
@ -3,18 +3,13 @@ import json
|
||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
import re
|
import re
|
||||||
import warnings
|
|
||||||
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit
|
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.staticfiles.utils import check_settings, matches_patterns
|
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.exceptions import ImproperlyConfigured
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.files.storage import FileSystemStorage, get_storage_class
|
from django.core.files.storage import FileSystemStorage, get_storage_class
|
||||||
from django.utils.deprecation import RemovedInDjango31Warning
|
|
||||||
from django.utils.functional import LazyObject
|
from django.utils.functional import LazyObject
|
||||||
|
|
||||||
|
|
||||||
|
@ -430,63 +425,6 @@ class ManifestFilesMixin(HashedFilesMixin):
|
||||||
return urlunsplit(unparsed_name)
|
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):
|
class ManifestStaticFilesStorage(ManifestFilesMixin, StaticFilesStorage):
|
||||||
"""
|
"""
|
||||||
A static file system storage backend which also saves
|
A static file system storage backend which also saves
|
||||||
|
|
|
@ -363,39 +363,6 @@ hashing algorithm.
|
||||||
.. _`url()`: https://www.w3.org/TR/CSS2/syndata.html#uri
|
.. _`url()`: https://www.w3.org/TR/CSS2/syndata.html#uri
|
||||||
.. _`Cascading Style Sheets`: https://www.w3.org/Style/CSS/
|
.. _`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</topics/cache>` 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``
|
``ManifestFilesMixin``
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|
|
@ -238,3 +238,5 @@ to remove usage of these features.
|
||||||
``django.contrib.postgres.forms.FloatRangeField`` are removed.
|
``django.contrib.postgres.forms.FloatRangeField`` are removed.
|
||||||
|
|
||||||
* The ``FILE_CHARSET`` setting is removed.
|
* The ``FILE_CHARSET`` setting is removed.
|
||||||
|
|
||||||
|
* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is removed.
|
||||||
|
|
|
@ -11,10 +11,8 @@ from django.contrib.staticfiles import finders, storage
|
||||||
from django.contrib.staticfiles.management.commands.collectstatic import (
|
from django.contrib.staticfiles.management.commands.collectstatic import (
|
||||||
Command as CollectstaticCommand,
|
Command as CollectstaticCommand,
|
||||||
)
|
)
|
||||||
from django.core.cache.backends.base import BaseCache
|
|
||||||
from django.core.management import call_command
|
from django.core.management import call_command
|
||||||
from django.test import SimpleTestCase, ignore_warnings, override_settings
|
from django.test import override_settings
|
||||||
from django.utils.deprecation import RemovedInDjango31Warning
|
|
||||||
|
|
||||||
from .cases import CollectionTestCase
|
from .cases import CollectionTestCase
|
||||||
from .settings import TEST_ROOT
|
from .settings import TEST_ROOT
|
||||||
|
@ -231,86 +229,6 @@ class TestHashedFiles:
|
||||||
self.assertPostCondition()
|
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')
|
@override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.ExtraPatternsStorage')
|
||||||
class TestExtraPatternsStorage(CollectionTestCase):
|
class TestExtraPatternsStorage(CollectionTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue