Skip to content

Commit

Permalink
Fixed #28606 -- Deprecated CachedStaticFilesStorage.
Browse files Browse the repository at this point in the history
  • Loading branch information
timgraham committed Oct 27, 2018
1 parent 55b0b76 commit 47ba87d
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 41 deletions.
10 changes: 9 additions & 1 deletion django/contrib/staticfiles/storage.py
Expand Up @@ -3,6 +3,7 @@
import os
import posixpath
import re
import warnings
from collections import OrderedDict
from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit

Expand All @@ -14,6 +15,7 @@
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


Expand Down Expand Up @@ -474,7 +476,13 @@ class CachedStaticFilesStorage(CachedFilesMixin, StaticFilesStorage):
A static file system storage backend which also saves
hashed copies of the files it saves.
"""
pass
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):
Expand Down
3 changes: 3 additions & 0 deletions docs/internals/deprecation.txt
Expand Up @@ -26,6 +26,9 @@ details on these changes.

* The ``FILE_CHARSET`` setting will be removed.

* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` will be
removed.

.. _deprecation-removed-in-3.0:

3.0
Expand Down
15 changes: 10 additions & 5 deletions docs/ref/contrib/staticfiles.txt
Expand Up @@ -62,7 +62,7 @@ The :djadmin:`collectstatic` management command calls the
method of the :setting:`STATICFILES_STORAGE` after each run and passes
a list of paths that have been found by the management command. It also
receives all command line options of :djadmin:`collectstatic`. This is used
by the :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
by the :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
by default.

By default, collected files receive permissions from
Expand Down Expand Up @@ -229,9 +229,7 @@ local development, should **never be used in production** and is only
available if the :doc:`staticfiles </ref/contrib/staticfiles>` app is
in your project's :setting:`INSTALLED_APPS` setting.

``--insecure`` doesn't work with
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` or
:class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`.
``--insecure`` doesn't work with :class:`~.storage.ManifestStaticFilesStorage`.

Example usage::

Expand Down Expand Up @@ -262,7 +260,7 @@ line options. It yields tuples of three values:
``processed`` is a boolean indicating whether or not the value was
post-processed, or an exception if post-processing failed.

The :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
The :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
uses this behind the scenes to replace the paths with their hashed
counterparts and update the cache appropriately.

Expand Down Expand Up @@ -362,6 +360,13 @@ hashing algorithm.

.. class:: storage.CachedStaticFilesStorage

.. deprecated:: 2.1

``CachedStaticFilesStorage`` is deprecated as it has some intractable
problems, some of which are outlind 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
Expand Down
5 changes: 1 addition & 4 deletions docs/releases/1.4.txt
Expand Up @@ -466,15 +466,12 @@ files from a cloud service<staticfiles-from-cdn>`.
--------------------------------------------

The :mod:`staticfiles<django.contrib.staticfiles>` contrib app now has a
:class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage` backend
``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` backend
that caches the files it saves (when running the :djadmin:`collectstatic`
management command) by appending the MD5 hash of the file's content to the
filename. For example, the file ``css/styles.css`` would also be saved as
``css/styles.55e7cbb9ba48.css``

See the :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
docs for more information.

Simple clickjacking protection
------------------------------

Expand Down
3 changes: 1 addition & 2 deletions docs/releases/1.7.txt
Expand Up @@ -506,8 +506,7 @@ Minor features
and :attr:`~django.core.files.storage.FileSystemStorage.directory_permissions_mode`
parameters. See :djadmin:`collectstatic` for example usage.

* The :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
backend gets a sibling class called
* The ``CachedStaticFilesStorage`` backend gets a sibling class called
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
that doesn't use the cache system at all but instead a JSON file called
``staticfiles.json`` for storing the mapping between the original file name
Expand Down
4 changes: 4 additions & 0 deletions docs/releases/2.2.txt
Expand Up @@ -354,3 +354,7 @@ Miscellaneous

* The ``FILE_CHARSET`` setting is deprecated. Starting with Django 3.1, files
read from disk must be UTF-8 encoded.

* ``django.contrib.staticfiles.storage.CachedStaticFilesStorage`` is
deprecated due to the intractable problems that is has. Use
:class:`.ManifestStaticFilesStorage` or a third-party cloud storage instead.
6 changes: 3 additions & 3 deletions docs/topics/performance.txt
Expand Up @@ -290,13 +290,13 @@ Static files
Static files, which by definition are not dynamic, make an excellent target for
optimization gains.

:class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By taking advantage of web browsers' caching abilities, you can
eliminate network hits entirely for a given file after the initial download.

:class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage` appends a
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` appends a
content-dependent tag to the filenames of :doc:`static files
</ref/contrib/staticfiles>` to make it safe for browsers to cache them
long-term without missing future changes - when a file changes, so will the
Expand Down
8 changes: 4 additions & 4 deletions tests/staticfiles_tests/storage.py
Expand Up @@ -2,7 +2,7 @@
from datetime import datetime, timedelta

from django.conf import settings
from django.contrib.staticfiles.storage import CachedStaticFilesStorage
from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
from django.core.files import storage
from django.utils import timezone

Expand Down Expand Up @@ -70,18 +70,18 @@ def url(self, path):
return path + '?a=b&c=d'


class SimpleCachedStaticFilesStorage(CachedStaticFilesStorage):
class SimpleStorage(ManifestStaticFilesStorage):

def file_hash(self, name, content=None):
return 'deploy12345'


class ExtraPatternsCachedStaticFilesStorage(CachedStaticFilesStorage):
class ExtraPatternsStorage(ManifestStaticFilesStorage):
"""
A storage class to test pattern substitutions with more than one pattern
entry. The added pattern rewrites strings like "url(...)" to JS_URL("...").
"""
patterns = tuple(CachedStaticFilesStorage.patterns) + (
patterns = tuple(ManifestStaticFilesStorage.patterns) + (
(
"*.js", (
(r"""(url\(['"]{0,1}\s*(.*?)["']{0,1}\))""", 'JS_URL("%s")'),
Expand Down
4 changes: 2 additions & 2 deletions tests/staticfiles_tests/test_management.py
Expand Up @@ -201,13 +201,13 @@ def test_verbosity_2(self):
self.assertIn(self.staticfiles_copied_msg, output)
self.assertIn(self.copying_msg, output)

@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.CachedStaticFilesStorage')
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage')
def test_verbosity_1_with_post_process(self):
stdout = StringIO()
self.run_collectstatic(verbosity=1, stdout=stdout, post_process=True)
self.assertNotIn(self.post_process_msg, stdout.getvalue())

@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.CachedStaticFilesStorage')
@override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage')
def test_verbosity_2_with_post_process(self):
stdout = StringIO()
self.run_collectstatic(verbosity=2, stdout=stdout, post_process=True)
Expand Down
41 changes: 22 additions & 19 deletions tests/staticfiles_tests/test_storage.py
Expand Up @@ -12,7 +12,8 @@
)
from django.core.cache.backends.base import BaseCache
from django.core.management import call_command
from django.test import override_settings
from django.test import SimpleTestCase, ignore_warnings, override_settings
from django.utils.deprecation import RemovedInDjango31Warning

from .cases import CollectionTestCase
from .settings import TEST_ROOT
Expand Down Expand Up @@ -43,9 +44,6 @@ def assertPostCondition(self):
pass

def test_template_tag_return(self):
"""
Test the CachedStaticFilesStorage backend.
"""
self.assertStaticRaises(ValueError, "does/not/exist.png", "/static/does/not/exist.png")
self.assertStaticRenders("test/file.txt", "/static/test/file.dad0999e4f8f.txt")
self.assertStaticRenders("test/file.txt", "/static/test/file.dad0999e4f8f.txt", asvar=True)
Expand Down Expand Up @@ -232,13 +230,15 @@ def test_post_processing_failure(self):
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
"""
@ignore_warnings(category=RemovedInDjango31Warning)
def test_cache_invalidation(self):
name = "cached/styles.css"
hashed_name = "cached/styles.5e0040571e1a.css"
Expand Down Expand Up @@ -282,6 +282,7 @@ def test_cache_key_memcache_validation(self):
cache_validator.validate_key(cache_key)
self.assertEqual(cache_key, 'staticfiles:821ea71ef36f95b3922a77f7364670e7')

@ignore_warnings(category=RemovedInDjango31Warning)
def test_corrupt_intermediate_files(self):
configured_storage = storage.staticfiles_storage
# Clear cache to force rehashing of the files
Expand All @@ -299,10 +300,20 @@ def test_corrupt_intermediate_files(self):
self.hashed_file_path('cached/styles.css')


@override_settings(
STATICFILES_STORAGE='staticfiles_tests.storage.ExtraPatternsCachedStaticFilesStorage',
)
class TestExtraPatternsCachedStorage(CollectionTestCase):
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):

def setUp(self):
storage.staticfiles_storage.hashed_files.clear() # avoid cache interference
Expand Down Expand Up @@ -437,23 +448,15 @@ def test_missing_entry(self):
self.hashed_file_path(missing_file_name)


@override_settings(
STATICFILES_STORAGE='staticfiles_tests.storage.SimpleCachedStaticFilesStorage',
)
class TestCollectionSimpleCachedStorage(CollectionTestCase):
"""
Tests for the Cache busting storage
"""
@override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.SimpleStorage')
class TestCollectionSimpleStorage(CollectionTestCase):
hashed_file_path = hashed_file_path

def setUp(self):
storage.staticfiles_storage.hashed_files.clear() # avoid cache interference
super().setUp()

def test_template_tag_return(self):
"""
Test the CachedStaticFilesStorage backend.
"""
self.assertStaticRaises(ValueError, "does/not/exist.png", "/static/does/not/exist.png")
self.assertStaticRenders("test/file.txt", "/static/test/file.deploy12345.txt")
self.assertStaticRenders("cached/styles.css", "/static/cached/styles.deploy12345.css")
Expand Down Expand Up @@ -543,7 +546,7 @@ def test_collect_static_files_subclass_of_static_storage(self):


@override_settings(
STATICFILES_STORAGE='django.contrib.staticfiles.storage.CachedStaticFilesStorage',
STATICFILES_STORAGE='django.contrib.staticfiles.storage.ManifestStaticFilesStorage',
)
class TestCollectionHashedFilesCache(CollectionTestCase):
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_utils/tests.py
Expand Up @@ -1092,7 +1092,7 @@ def test_override_staticfiles_storage(self):
Overriding the STATICFILES_STORAGE setting should be reflected in
the value of django.contrib.staticfiles.storage.staticfiles_storage.
"""
new_class = 'CachedStaticFilesStorage'
new_class = 'ManifestStaticFilesStorage'
new_storage = 'django.contrib.staticfiles.storage.' + new_class
with self.settings(STATICFILES_STORAGE=new_storage):
self.assertEqual(staticfiles_storage.__class__.__name__, new_class)
Expand Down

0 comments on commit 47ba87d

Please sign in to comment.