Browse Source

Refs #26029 -- Deprecated DEFAULT_FILE_STORAGE and STATICFILES_STORAGE settings.

Jarosław Wygoda 2 years ago
parent
commit
32940d390a

+ 61 - 1
django/conf/__init__.py

@@ -16,10 +16,12 @@ from pathlib import Path
 import django
 from django.conf import global_settings
 from django.core.exceptions import ImproperlyConfigured
-from django.utils.deprecation import RemovedInDjango50Warning
+from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
 from django.utils.functional import LazyObject, empty
 
 ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
+DEFAULT_STORAGE_ALIAS = "default"
+STATICFILES_STORAGE_ALIAS = "staticfiles"
 
 # RemovedInDjango50Warning
 USE_DEPRECATED_PYTZ_DEPRECATED_MSG = (
@@ -39,6 +41,14 @@ CSRF_COOKIE_MASKED_DEPRECATED_MSG = (
     "it will be removed in Django 5.0."
 )
 
+DEFAULT_FILE_STORAGE_DEPRECATED_MSG = (
+    "The DEFAULT_FILE_STORAGE setting is deprecated. Use STORAGES instead."
+)
+
+STATICFILES_STORAGE_DEPRECATED_MSG = (
+    "The STATICFILES_STORAGE setting is deprecated. Use STORAGES instead."
+)
+
 
 class SettingsReference(str):
     """
@@ -177,6 +187,22 @@ class LazySettings(LazyObject):
         # paths.
         return self.__getattr__("USE_L10N")
 
+    # RemovedInDjango51Warning.
+    @property
+    def DEFAULT_FILE_STORAGE(self):
+        self._show_deprecation_warning(
+            DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning
+        )
+        return self.__getattr__("DEFAULT_FILE_STORAGE")
+
+    # RemovedInDjango51Warning.
+    @property
+    def STATICFILES_STORAGE(self):
+        self._show_deprecation_warning(
+            STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning
+        )
+        return self.__getattr__("STATICFILES_STORAGE")
+
 
 class Settings:
     def __init__(self, settings_module):
@@ -240,6 +266,20 @@ class Settings:
         if self.is_overridden("USE_L10N"):
             warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
 
+        if self.is_overridden("DEFAULT_FILE_STORAGE"):
+            if self.is_overridden("STORAGES"):
+                raise ImproperlyConfigured(
+                    "DEFAULT_FILE_STORAGE/STORAGES are mutually exclusive."
+                )
+            warnings.warn(DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
+
+        if self.is_overridden("STATICFILES_STORAGE"):
+            if self.is_overridden("STORAGES"):
+                raise ImproperlyConfigured(
+                    "STATICFILES_STORAGE/STORAGES are mutually exclusive."
+                )
+            warnings.warn(STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
+
     def is_overridden(self, setting):
         return setting in self._explicit_settings
 
@@ -276,9 +316,29 @@ class UserSettingsHolder:
             warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
         if name == "CSRF_COOKIE_MASKED":
             warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning)
+        if name == "DEFAULT_FILE_STORAGE":
+            self.STORAGES[DEFAULT_STORAGE_ALIAS] = {
+                "BACKEND": self.DEFAULT_FILE_STORAGE
+            }
+            warnings.warn(DEFAULT_FILE_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
+        if name == "STATICFILES_STORAGE":
+            self.STORAGES[STATICFILES_STORAGE_ALIAS] = {
+                "BACKEND": self.STATICFILES_STORAGE
+            }
+            warnings.warn(STATICFILES_STORAGE_DEPRECATED_MSG, RemovedInDjango51Warning)
         super().__setattr__(name, value)
         if name == "USE_DEPRECATED_PYTZ":
             warnings.warn(USE_DEPRECATED_PYTZ_DEPRECATED_MSG, RemovedInDjango50Warning)
+        # RemovedInDjango51Warning.
+        if name == "STORAGES":
+            self.STORAGES.setdefault(
+                DEFAULT_STORAGE_ALIAS,
+                {"BACKEND": "django.core.files.storage.FileSystemStorage"},
+            )
+            self.STORAGES.setdefault(
+                STATICFILES_STORAGE_ALIAS,
+                {"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage"},
+            )
 
     def __delattr__(self, name):
         self._deleted.add(name)

+ 8 - 1
django/conf/global_settings.py

@@ -280,7 +280,14 @@ SECRET_KEY_FALLBACKS = []
 # Default file storage mechanism that holds media.
 DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
 
-STORAGES = {}
+STORAGES = {
+    "default": {
+        "BACKEND": "django.core.files.storage.FileSystemStorage",
+    },
+    "staticfiles": {
+        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
+    },
+}
 
 # Absolute filesystem path to the directory that will hold user-uploaded files.
 # Example: "/var/www/example.com/media/"

+ 3 - 3
django/contrib/staticfiles/storage.py

@@ -4,11 +4,11 @@ import posixpath
 import re
 from urllib.parse import unquote, urldefrag, urlsplit, urlunsplit
 
-from django.conf import settings
+from django.conf import STATICFILES_STORAGE_ALIAS, settings
 from django.contrib.staticfiles.utils import check_settings, matches_patterns
 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.core.files.storage import FileSystemStorage, storages
 from django.utils.crypto import md5
 from django.utils.functional import LazyObject
 
@@ -526,7 +526,7 @@ class ManifestStaticFilesStorage(ManifestFilesMixin, StaticFilesStorage):
 
 class ConfiguredStorage(LazyObject):
     def _setup(self):
-        self._wrapped = get_storage_class(settings.STATICFILES_STORAGE)()
+        self._wrapped = storages[STATICFILES_STORAGE_ALIAS]
 
 
 staticfiles_storage = ConfiguredStorage()

+ 11 - 2
django/core/files/storage/__init__.py

@@ -1,4 +1,7 @@
-from django.conf import settings
+import warnings
+
+from django.conf import DEFAULT_STORAGE_ALIAS, settings
+from django.utils.deprecation import RemovedInDjango51Warning
 from django.utils.functional import LazyObject
 from django.utils.module_loading import import_string
 
@@ -19,14 +22,20 @@ __all__ = (
     "storages",
 )
 
+GET_STORAGE_CLASS_DEPRECATED_MSG = (
+    "django.core.files.storage.get_storage_class is deprecated in favor of "
+    "using django.core.files.storage.storages."
+)
+
 
 def get_storage_class(import_path=None):
+    warnings.warn(GET_STORAGE_CLASS_DEPRECATED_MSG, RemovedInDjango51Warning)
     return import_string(import_path or settings.DEFAULT_FILE_STORAGE)
 
 
 class DefaultStorage(LazyObject):
     def _setup(self):
-        self._wrapped = get_storage_class()()
+        self._wrapped = storages[DEFAULT_STORAGE_ALIAS]
 
 
 storages = StorageHandler()

+ 10 - 1
django/core/files/storage/handler.py

@@ -1,4 +1,4 @@
-from django.conf import settings
+from django.conf import DEFAULT_STORAGE_ALIAS, STATICFILES_STORAGE_ALIAS, settings
 from django.core.exceptions import ImproperlyConfigured
 from django.utils.functional import cached_property
 from django.utils.module_loading import import_string
@@ -19,6 +19,15 @@ class StorageHandler:
     def backends(self):
         if self._backends is None:
             self._backends = settings.STORAGES.copy()
+            # RemovedInDjango51Warning.
+            if settings.is_overridden("DEFAULT_FILE_STORAGE"):
+                self._backends[DEFAULT_STORAGE_ALIAS] = {
+                    "BACKEND": settings.DEFAULT_FILE_STORAGE
+                }
+            if settings.is_overridden("STATICFILES_STORAGE"):
+                self._backends[STATICFILES_STORAGE_ALIAS] = {
+                    "BACKEND": settings.STATICFILES_STORAGE
+                }
         return self._backends
 
     def __getitem__(self, alias):

+ 25 - 2
django/test/signals.py

@@ -13,6 +13,7 @@ from django.dispatch import Signal, receiver
 from django.utils import timezone
 from django.utils.formats import FORMAT_SETTINGS, reset_format_cache
 from django.utils.functional import empty
+from django.utils.module_loading import import_string
 
 template_rendered = Signal()
 
@@ -113,7 +114,8 @@ def reset_template_engines(*, setting, **kwargs):
 
 @receiver(setting_changed)
 def storages_changed(*, setting, **kwargs):
-    from django.core.files.storage import storages
+    from django.contrib.staticfiles.storage import staticfiles_storage
+    from django.core.files.storage import default_storage, storages
 
     if setting in (
         "STORAGES",
@@ -127,6 +129,9 @@ def storages_changed(*, setting, **kwargs):
         storages._backends = None
         storages._storages = {}
 
+        default_storage._wrapped = empty
+        staticfiles_storage._wrapped = empty
+
 
 @receiver(setting_changed)
 def clear_serializers_cache(*, setting, **kwargs):
@@ -156,11 +161,18 @@ def localize_settings_changed(*, setting, **kwargs):
         reset_format_cache()
 
 
+# RemovedInDjango51Warning.
 @receiver(setting_changed)
 def file_storage_changed(*, setting, **kwargs):
     if setting == "DEFAULT_FILE_STORAGE":
-        from django.core.files.storage import default_storage
+        from django.conf import DEFAULT_STORAGE_ALIAS
+        from django.core.files.storage import default_storage, storages
 
+        try:
+            del storages.backends
+        except AttributeError:
+            pass
+        storages._storages[DEFAULT_STORAGE_ALIAS] = import_string(kwargs["value"])()
         default_storage._wrapped = empty
 
 
@@ -195,6 +207,17 @@ def static_storage_changed(*, setting, **kwargs):
 
         staticfiles_storage._wrapped = empty
 
+    # RemovedInDjango51Warning.
+    if setting == "STATICFILES_STORAGE":
+        from django.conf import STATICFILES_STORAGE_ALIAS
+        from django.core.files.storage import storages
+
+        try:
+            del storages.backends
+        except AttributeError:
+            pass
+        storages._storages[STATICFILES_STORAGE_ALIAS] = import_string(kwargs["value"])()
+
 
 @receiver(setting_changed)
 def static_finders_changed(*, setting, **kwargs):

+ 12 - 5
docs/howto/static-files/deployment.txt

@@ -15,8 +15,8 @@ Serving static files in production
 The basic outline of putting static files into production consists of two
 steps: run the :djadmin:`collectstatic` command when static files change, then
 arrange for the collected static files directory (:setting:`STATIC_ROOT`) to be
-moved to the static file server and served. Depending on
-:setting:`STATICFILES_STORAGE`, files may need to be moved to a new location
+moved to the static file server and served. Depending the ``staticfiles``
+:setting:`STORAGES` alias, files may need to be moved to a new location
 manually or the :func:`post_process
 <django.contrib.staticfiles.storage.StaticFilesStorage.post_process>` method of
 the ``Storage`` class might take care of that.
@@ -85,17 +85,20 @@ There's any number of ways you might do this, but if the provider has an API,
 you can use a :doc:`custom file storage backend </howto/custom-file-storage>`
 to integrate the CDN with your Django project. If you've written or are using a
 3rd party custom storage backend, you can tell :djadmin:`collectstatic` to use
-it by setting :setting:`STATICFILES_STORAGE` to the storage engine.
+it by setting ``staticfiles`` in :setting:`STORAGES`.
 
 For example, if you've written an S3 storage backend in
 ``myproject.storage.S3Storage`` you could use it with::
 
-    STATICFILES_STORAGE = 'myproject.storage.S3Storage'
+    STORAGES = {
+        # ...
+        "staticfiles": {"BACKEND": "myproject.storage.S3Storage"}
+    }
 
 Once that's done, all you have to do is run :djadmin:`collectstatic` and your
 static files would be pushed through your storage package up to S3. If you
 later needed to switch to a different storage provider, you may only have to
-change your :setting:`STATICFILES_STORAGE` setting.
+change ``staticfiles`` in the :setting:`STORAGES` setting.
 
 For details on how you'd write one of these backends, see
 :doc:`/howto/custom-file-storage`. There are 3rd party apps available that
@@ -103,6 +106,10 @@ provide storage backends for many common file storage APIs. A good starting
 point is the `overview at djangopackages.org
 <https://djangopackages.org/grids/g/storage-backends/>`_.
 
+.. versionchanged:: 4.2
+
+    The :setting:`STORAGES` setting was added.
+
 Learn more
 ==========
 

+ 2 - 1
docs/howto/static-files/index.txt

@@ -19,7 +19,8 @@ Configuring static files
       STATIC_URL = 'static/'
 
 #. In your templates, use the :ttag:`static` template tag to build the URL for
-   the given relative path using the configured :setting:`STATICFILES_STORAGE`.
+   the given relative path using the configured ``staticfiles``
+   :setting:`STORAGES` alias.
 
    .. _staticfiles-in-templates:
 

+ 6 - 0
docs/internals/deprecation.txt

@@ -45,6 +45,12 @@ details on these changes.
 * Support for passing positional arguments to ``Signer`` and
   ``TimestampSigner`` will be removed.
 
+* The ``DEFAULT_FILE_STORAGE`` and ``STATICFILES_STORAGE`` settings will be
+  removed.
+
+* The ``django.core.files.storage.get_storage_class()`` function will be
+  removed.
+
 .. _deprecation-removed-in-5.0:
 
 5.0

+ 18 - 12
docs/ref/contrib/staticfiles.txt

@@ -60,11 +60,12 @@ specified by the :setting:`INSTALLED_APPS` setting.
 
 The :djadmin:`collectstatic` management command calls the
 :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
-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.ManifestStaticFilesStorage`
-by default.
+method of the ``staticfiles`` storage backend from :setting:`STORAGES` 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.ManifestStaticFilesStorage` by
+default.
 
 By default, collected files receive permissions from
 :setting:`FILE_UPLOAD_PERMISSIONS` and collected directories receive permissions
@@ -82,7 +83,7 @@ respectively. For example::
             kwargs['directory_permissions_mode'] = 0o760
             super().__init__(*args, **kwargs)
 
-Then set the :setting:`STATICFILES_STORAGE` setting to
+Then set the ``staticfiles`` storage backend in :setting:`STORAGES` setting to
 ``'path.to.MyStaticFilesStorage'``.
 
 Some commonly used options are:
@@ -113,7 +114,8 @@ Some commonly used options are:
 
     Don't call the
     :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
-    method of the configured :setting:`STATICFILES_STORAGE` storage backend.
+    method of the configured ``staticfiles`` storage backend from
+    :setting:`STORAGES`.
 
 .. django-admin-option:: --no-default-ignore
 
@@ -360,7 +362,7 @@ attribute. It defaults to 5.
 To enable the ``ManifestStaticFilesStorage`` you have to make sure the
 following requirements are met:
 
-* the :setting:`STATICFILES_STORAGE` setting is set to
+* the ``staticfiles`` storage backend in :setting:`STORAGES` setting is set to
   ``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'``
 * the :setting:`DEBUG` setting is set to ``False``
 * you've collected all your static files by using the
@@ -381,9 +383,9 @@ If a file isn't found in the ``staticfiles.json`` manifest at runtime, a
 
 Due to the requirement of running :djadmin:`collectstatic`, this storage
 typically shouldn't be used when running tests as ``collectstatic`` isn't run
-as part of the normal test setup. During testing, ensure that the
-:setting:`STATICFILES_STORAGE` setting is set to something else like
-``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default).
+as part of the normal test setup. During testing, ensure that ``staticfiles``
+storage backend in the :setting:`STORAGES` setting is set to something else
+like ``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default).
 
 .. method:: storage.ManifestStaticFilesStorage.file_hash(name, content=None)
 
@@ -434,7 +436,8 @@ files:
 - The builtin template tag :ttag:`static` which takes a path and urljoins it
   with the static prefix :setting:`STATIC_URL`. If
   ``django.contrib.staticfiles`` is installed, the tag uses the ``url()``
-  method of the :setting:`STATICFILES_STORAGE` instead.
+  method of the ``staticfiles`` storage backend from :setting:`STORAGES`
+  instead.
 
 - The builtin template tag :ttag:`get_static_prefix` which populates a
   template variable with the static prefix :setting:`STATIC_URL` to be
@@ -443,6 +446,9 @@ files:
 - The similar template tag :ttag:`get_media_prefix` which works like
   :ttag:`get_static_prefix` but uses :setting:`MEDIA_URL`.
 
+- The ``staticfiles`` key in :data:`django.core.files.storage.storages`
+  contains a ready-to-use instance of the staticfiles storage backend.
+
 .. _staticfiles-development-view:
 
 Static file development view

+ 13 - 8
docs/ref/files/storage.txt

@@ -18,9 +18,9 @@ Django provides convenient ways to access the default storage class:
 .. class:: DefaultStorage
 
     :class:`~django.core.files.storage.DefaultStorage` provides
-    lazy access to the current default storage system as defined by
-    :setting:`DEFAULT_FILE_STORAGE`. :class:`DefaultStorage` uses
-    :func:`~django.core.files.storage.get_storage_class` internally.
+    lazy access to the default storage system as defined by ``default`` key in
+    :setting:`STORAGES`. :class:`DefaultStorage` uses
+    :data:`~django.core.files.storage.storages` internally.
 
 .. data:: default_storage
 
@@ -32,11 +32,16 @@ Django provides convenient ways to access the default storage class:
     Returns a class or module which implements the storage API.
 
     When called without the ``import_path`` parameter ``get_storage_class``
-    will return the current default storage system as defined by
-    :setting:`DEFAULT_FILE_STORAGE`. If ``import_path`` is provided,
-    ``get_storage_class`` will attempt to import the class or module from the
-    given path and will return it if successful. An exception will be
-    raised if the import is unsuccessful.
+    will return the default storage system as defined by ``default`` key in
+    :setting:`STORAGES`. If ``import_path`` is provided, ``get_storage_class``
+    will attempt to import the class or module from the given path and will
+    return it if successful. An exception will be raised if the import is
+    unsuccessful.
+
+    .. deprecated:: 4.2
+
+        The ``get_storage_class()`` function is deprecated. Use
+        :data:`storages` instead
 
 The ``FileSystemStorage`` class
 ===============================

+ 32 - 5
docs/ref/settings.txt

@@ -1356,6 +1356,12 @@ Default: ``'``:class:`django.core.files.storage.FileSystemStorage`\ ``'``
 Default file storage class to be used for any file-related operations that don't
 specify a particular storage system. See :doc:`/topics/files`.
 
+.. deprecated:: 4.2
+
+    This setting is deprecated. Starting with Django 4.2, default file storage
+    engine can be configured with the :setting:`STORAGES` setting under the
+    ``default`` key.
+
 .. setting:: DEFAULT_FROM_EMAIL
 
 ``DEFAULT_FROM_EMAIL``
@@ -2615,13 +2621,28 @@ See also the :doc:`/ref/checks` documentation.
 
 Default::
 
-    {}
+    {
+        "default": {
+            "BACKEND": "django.core.files.storage.FileSystemStorage",
+        },
+        "staticfiles": {
+            "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
+        },
+    }
 
 A dictionary containing the settings for all storages to be used with Django.
 It is a nested dictionary whose contents map a storage alias to a dictionary
 containing the options for an individual storage.
 
-Storages can have any alias you choose.
+Storages can have any alias you choose. However, there are two aliases with
+special significance:
+
+* ``default`` for :doc:`managing files </topics/files>`.
+  ``'``:class:`django.core.files.storage.FileSystemStorage`\ ``'`` is the
+  default storage engine.
+* ``staticfiles`` for :doc:`managing static files </ref/contrib/staticfiles>`.
+  ``'``:class:`django.contrib.staticfiles.storage.StaticFilesStorage`\ ``'`` is
+  the default storage engine.
 
 The following is an example ``settings.py`` snippet defining a custom file
 storage called ``example``::
@@ -3598,10 +3619,16 @@ The file storage engine to use when collecting static files with the
 :djadmin:`collectstatic` management command.
 
 A ready-to-use instance of the storage backend defined in this setting
-can be found at ``django.contrib.staticfiles.storage.staticfiles_storage``.
+can be found under ``staticfiles`` key in ``django.core.files.storage.storages``.
 
 For an example, see :ref:`staticfiles-from-cdn`.
 
+.. deprecated:: 4.2
+
+    This setting is deprecated. Starting with Django 4.2, static files storage
+    engine can be configured with the :setting:`STORAGES` setting under the
+    ``staticfiles`` key.
+
 .. setting:: STATICFILES_FINDERS
 
 ``STATICFILES_FINDERS``
@@ -3627,8 +3654,8 @@ used.
 One finder is disabled by default:
 ``django.contrib.staticfiles.finders.DefaultStorageFinder``. If added to
 your :setting:`STATICFILES_FINDERS` setting, it will look for static files in
-the default file storage as defined by the :setting:`DEFAULT_FILE_STORAGE`
-setting.
+the default file storage as defined by the ``default`` key in the
+:setting:`STORAGES` setting.
 
 .. note::
 

+ 1 - 1
docs/ref/templates/builtins.txt

@@ -2629,7 +2629,7 @@ A set of Django template filters useful for adding a "human touch" to data. See
 To link to static files that are saved in :setting:`STATIC_ROOT` Django ships
 with a :ttag:`static` template tag. If the :mod:`django.contrib.staticfiles`
 app is installed, the tag will serve files using ``url()`` method of the
-storage specified by :setting:`STATICFILES_STORAGE`. For example::
+storage specified by ``staticfiles`` in :setting:`STORAGES`. For example::
 
     {% load static %}
     <img src="{% static 'images/hi.jpg' %}" alt="Hi!">

+ 14 - 1
docs/releases/4.2.txt

@@ -95,7 +95,12 @@ Custom file storages
 --------------------
 
 The new :setting:`STORAGES` setting allows configuring multiple custom file
-storage backends.
+storage backends. It also controls storage engines for managing
+:doc:`files </topics/files>` (the ``"defaut"`` key) and :doc:`static files
+</ref/contrib/staticfiles>` (the ``"staticfiles"`` key).
+
+The old ``DEFAULT_FILE_STORAGE`` and ``STATICFILES_STORAGE`` settings are
+deprecated as of this release.
 
 Minor features
 --------------
@@ -674,3 +679,11 @@ Miscellaneous
 
 * Passing positional arguments to ``Signer`` and ``TimestampSigner`` is
   deprecated in favor of keyword-only arguments.
+
+* The ``DEFAULT_FILE_STORAGE`` setting is deprecated in favor of
+  ``STORAGES["default"]``.
+
+* The ``STATICFILES_STORAGE`` setting is deprecated in favor of
+  ``STORAGES["staticfiles"]``.
+
+* The ``django.core.files.storage.get_storage_class()`` function is deprecated.

+ 4 - 3
docs/topics/files.txt

@@ -156,9 +156,10 @@ Behind the scenes, Django delegates decisions about how and where to store files
 to a file storage system. This is the object that actually understands things
 like file systems, opening and reading files, etc.
 
-Django's default file storage is given by the :setting:`DEFAULT_FILE_STORAGE`
-setting; if you don't explicitly provide a storage system, this is the one that
-will be used.
+Django's default file storage is
+``'``:class:`django.core.files.storage.FileSystemStorage`\ ``'``. If you don't
+explicitly provide a storage system in the ``default`` key of the
+:setting:`STORAGES` setting, this is the one that will be used.
 
 See below for details of the built-in default file storage system, and see
 :doc:`/howto/custom-file-storage` for information on writing your own file

+ 9 - 10
docs/topics/testing/tools.txt

@@ -1441,16 +1441,15 @@ when settings are changed.
 
 Django itself uses this signal to reset various data:
 
-================================= ========================
-Overridden settings               Data reset
-================================= ========================
-USE_TZ, TIME_ZONE                 Databases timezone
-TEMPLATES                         Template engines
-SERIALIZATION_MODULES             Serializers cache
-LOCALE_PATHS, LANGUAGE_CODE       Default translation and loaded translations
-MEDIA_ROOT, DEFAULT_FILE_STORAGE  Default file storage
-STATIC_ROOT, STATIC_URL, STORAGES Storages configuration
-================================= ========================
+============================================================================ ========================
+Overridden settings                                                          Data reset
+============================================================================ ========================
+USE_TZ, TIME_ZONE                                                            Databases timezone
+TEMPLATES                                                                    Template engines
+SERIALIZATION_MODULES                                                        Serializers cache
+LOCALE_PATHS, LANGUAGE_CODE                                                  Default translation and loaded translations
+DEFAULT_FILE_STORAGE, STATICFILES_STORAGE, STATIC_ROOT, STATIC_URL, STORAGES Storages configuration
+============================================================================ ========================
 
 Isolating apps
 --------------

+ 165 - 0
tests/deprecation/test_storages.py

@@ -0,0 +1,165 @@
+import sys
+from types import ModuleType
+
+from django.conf import (
+    DEFAULT_FILE_STORAGE_DEPRECATED_MSG,
+    DEFAULT_STORAGE_ALIAS,
+    STATICFILES_STORAGE_ALIAS,
+    STATICFILES_STORAGE_DEPRECATED_MSG,
+    Settings,
+    settings,
+)
+from django.contrib.staticfiles.storage import (
+    ManifestStaticFilesStorage,
+    staticfiles_storage,
+)
+from django.core.exceptions import ImproperlyConfigured
+from django.core.files.storage import Storage, StorageHandler, default_storage, storages
+from django.test import TestCase, ignore_warnings
+from django.utils.deprecation import RemovedInDjango51Warning
+
+
+class StaticfilesStorageDeprecationTests(TestCase):
+    msg = STATICFILES_STORAGE_DEPRECATED_MSG
+
+    def test_override_settings_warning(self):
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            with self.settings(
+                STATICFILES_STORAGE=(
+                    "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+                )
+            ):
+                pass
+
+    def test_settings_init(self):
+        settings_module = ModuleType("fake_settings_module")
+        settings_module.USE_TZ = True
+        settings_module.STATICFILES_STORAGE = (
+            "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+        )
+        sys.modules["fake_settings_module"] = settings_module
+        try:
+            with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+                Settings("fake_settings_module")
+        finally:
+            del sys.modules["fake_settings_module"]
+
+    def test_access_warning(self):
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            settings.STATICFILES_STORAGE
+        # Works a second time.
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            settings.STATICFILES_STORAGE
+
+    @ignore_warnings(category=RemovedInDjango51Warning)
+    def test_access(self):
+        with self.settings(
+            STATICFILES_STORAGE=(
+                "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+            )
+        ):
+            self.assertEqual(
+                settings.STATICFILES_STORAGE,
+                "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+            )
+            # Works a second time.
+            self.assertEqual(
+                settings.STATICFILES_STORAGE,
+                "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+            )
+
+    def test_use_both_error(self):
+        msg = "STATICFILES_STORAGE/STORAGES are mutually exclusive."
+        settings_module = ModuleType("fake_settings_module")
+        settings_module.USE_TZ = True
+        settings_module.STATICFILES_STORAGE = (
+            "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+        )
+        settings_module.STORAGES = {}
+        sys.modules["fake_settings_module"] = settings_module
+        try:
+            with self.assertRaisesMessage(ImproperlyConfigured, msg):
+                Settings("fake_settings_module")
+        finally:
+            del sys.modules["fake_settings_module"]
+
+    @ignore_warnings(category=RemovedInDjango51Warning)
+    def test_storage(self):
+        empty_storages = StorageHandler()
+        with self.settings(
+            STATICFILES_STORAGE=(
+                "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+            )
+        ):
+            self.assertIsInstance(
+                storages[STATICFILES_STORAGE_ALIAS],
+                ManifestStaticFilesStorage,
+            )
+            self.assertIsInstance(
+                empty_storages[STATICFILES_STORAGE_ALIAS],
+                ManifestStaticFilesStorage,
+            )
+            self.assertIsInstance(staticfiles_storage, ManifestStaticFilesStorage)
+
+
+class DefaultStorageDeprecationTests(TestCase):
+    msg = DEFAULT_FILE_STORAGE_DEPRECATED_MSG
+
+    def test_override_settings_warning(self):
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            with self.settings(
+                DEFAULT_FILE_STORAGE=("django.core.files.storage.Storage")
+            ):
+                pass
+
+    def test_settings_init(self):
+        settings_module = ModuleType("fake_settings_module")
+        settings_module.USE_TZ = True
+        settings_module.DEFAULT_FILE_STORAGE = "django.core.files.storage.Storage"
+        sys.modules["fake_settings_module"] = settings_module
+        try:
+            with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+                Settings("fake_settings_module")
+        finally:
+            del sys.modules["fake_settings_module"]
+
+    def test_access_warning(self):
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            settings.DEFAULT_FILE_STORAGE
+        # Works a second time.
+        with self.assertRaisesMessage(RemovedInDjango51Warning, self.msg):
+            settings.DEFAULT_FILE_STORAGE
+
+    @ignore_warnings(category=RemovedInDjango51Warning)
+    def test_access(self):
+        with self.settings(DEFAULT_FILE_STORAGE="django.core.files.storage.Storage"):
+            self.assertEqual(
+                settings.DEFAULT_FILE_STORAGE,
+                "django.core.files.storage.Storage",
+            )
+            # Works a second time.
+            self.assertEqual(
+                settings.DEFAULT_FILE_STORAGE,
+                "django.core.files.storage.Storage",
+            )
+
+    def test_use_both_error(self):
+        msg = "DEFAULT_FILE_STORAGE/STORAGES are mutually exclusive."
+        settings_module = ModuleType("fake_settings_module")
+        settings_module.USE_TZ = True
+        settings_module.DEFAULT_FILE_STORAGE = "django.core.files.storage.Storage"
+        settings_module.STORAGES = {}
+        sys.modules["fake_settings_module"] = settings_module
+        try:
+            with self.assertRaisesMessage(ImproperlyConfigured, msg):
+                Settings("fake_settings_module")
+        finally:
+            del sys.modules["fake_settings_module"]
+
+    @ignore_warnings(category=RemovedInDjango51Warning)
+    def test_storage(self):
+        empty_storages = StorageHandler()
+        with self.settings(DEFAULT_FILE_STORAGE="django.core.files.storage.Storage"):
+            self.assertIsInstance(storages[DEFAULT_STORAGE_ALIAS], Storage)
+            self.assertIsInstance(empty_storages[DEFAULT_STORAGE_ALIAS], Storage)
+            self.assertIsInstance(default_storage, Storage)

+ 28 - 3
tests/file_storage/tests.py

@@ -11,10 +11,15 @@ from io import StringIO
 from pathlib import Path
 from urllib.request import urlopen
 
+from django.conf import DEFAULT_STORAGE_ALIAS, STATICFILES_STORAGE_ALIAS
 from django.core.cache import cache
 from django.core.exceptions import SuspiciousFileOperation
 from django.core.files.base import ContentFile, File
-from django.core.files.storage import FileSystemStorage, InvalidStorageError
+from django.core.files.storage import (
+    GET_STORAGE_CLASS_DEPRECATED_MSG,
+    FileSystemStorage,
+    InvalidStorageError,
+)
 from django.core.files.storage import Storage as BaseStorage
 from django.core.files.storage import (
     StorageHandler,
@@ -30,10 +35,11 @@ from django.core.files.uploadedfile import (
 from django.db.models import FileField
 from django.db.models.fields.files import FileDescriptor
 from django.test import LiveServerTestCase, SimpleTestCase, TestCase, override_settings
-from django.test.utils import requires_tz_support
+from django.test.utils import ignore_warnings, requires_tz_support
 from django.urls import NoReverseMatch, reverse_lazy
 from django.utils import timezone
 from django.utils._os import symlinks_supported
+from django.utils.deprecation import RemovedInDjango51Warning
 
 from .models import Storage, callable_storage, temp_storage, temp_storage_location
 
@@ -41,6 +47,7 @@ FILE_SUFFIX_REGEX = "[A-Za-z0-9]{7}"
 
 
 class GetStorageClassTests(SimpleTestCase):
+    @ignore_warnings(category=RemovedInDjango51Warning)
     def test_get_filesystem_storage(self):
         """
         get_storage_class returns the class for a storage backend name/path.
@@ -50,6 +57,7 @@ class GetStorageClassTests(SimpleTestCase):
             FileSystemStorage,
         )
 
+    @ignore_warnings(category=RemovedInDjango51Warning)
     def test_get_invalid_storage_module(self):
         """
         get_storage_class raises an error if the requested import don't exist.
@@ -57,6 +65,7 @@ class GetStorageClassTests(SimpleTestCase):
         with self.assertRaisesMessage(ImportError, "No module named 'storage'"):
             get_storage_class("storage.NonexistentStorage")
 
+    @ignore_warnings(category=RemovedInDjango51Warning)
     def test_get_nonexistent_storage_class(self):
         """
         get_storage_class raises an error if the requested class don't exist.
@@ -64,6 +73,7 @@ class GetStorageClassTests(SimpleTestCase):
         with self.assertRaises(ImportError):
             get_storage_class("django.core.files.storage.NonexistentStorage")
 
+    @ignore_warnings(category=RemovedInDjango51Warning)
     def test_get_nonexistent_storage_module(self):
         """
         get_storage_class raises an error if the requested module don't exist.
@@ -75,6 +85,11 @@ class GetStorageClassTests(SimpleTestCase):
                 "django.core.files.nonexistent_storage.NonexistentStorage"
             )
 
+    def test_deprecation_warning(self):
+        msg = GET_STORAGE_CLASS_DEPRECATED_MSG
+        with self.assertRaisesMessage(RemovedInDjango51Warning, msg):
+            get_storage_class("django.core.files.storage.FileSystemStorage"),
+
 
 class FileSystemStorageTests(unittest.TestCase):
     def test_deconstruction(self):
@@ -1179,7 +1194,17 @@ class StorageHandlerTests(SimpleTestCase):
 
     def test_defaults(self):
         storages = StorageHandler()
-        self.assertEqual(storages.backends, {})
+        self.assertEqual(
+            storages.backends,
+            {
+                DEFAULT_STORAGE_ALIAS: {
+                    "BACKEND": "django.core.files.storage.FileSystemStorage",
+                },
+                STATICFILES_STORAGE_ALIAS: {
+                    "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
+                },
+            },
+        )
 
     def test_nonexistent_alias(self):
         msg = "Could not find config for 'nonexistent' in settings.STORAGES."

+ 6 - 1
tests/file_uploads/tests.py

@@ -9,6 +9,7 @@ from io import BytesIO, StringIO
 from unittest import mock
 from urllib.parse import quote
 
+from django.conf import DEFAULT_STORAGE_ALIAS
 from django.core.exceptions import SuspiciousFileOperation
 from django.core.files import temp as tempfile
 from django.core.files.storage import default_storage
@@ -806,7 +807,11 @@ class DirectoryCreationTests(SimpleTestCase):
         sys.platform == "win32", "Python on Windows doesn't have working os.chmod()."
     )
     @override_settings(
-        DEFAULT_FILE_STORAGE="django.core.files.storage.FileSystemStorage"
+        STORAGES={
+            DEFAULT_STORAGE_ALIAS: {
+                "BACKEND": "django.core.files.storage.FileSystemStorage",
+            }
+        }
     )
     def test_readonly_root(self):
         """Permission errors are not swallowed"""

+ 7 - 2
tests/staticfiles_tests/test_forms.py

@@ -1,5 +1,6 @@
 from urllib.parse import urljoin
 
+from django.conf import STATICFILES_STORAGE_ALIAS
 from django.contrib.staticfiles import storage
 from django.forms import Media
 from django.templatetags.static import static
@@ -12,9 +13,13 @@ class StaticTestStorage(storage.StaticFilesStorage):
 
 
 @override_settings(
-    STATIC_URL="http://media.example.com/static/",
     INSTALLED_APPS=("django.contrib.staticfiles",),
-    STATICFILES_STORAGE="staticfiles_tests.test_forms.StaticTestStorage",
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.test_forms.StaticTestStorage",
+            "OPTIONS": {"location": "http://media.example.com/static/"},
+        }
+    },
 )
 class StaticFilesFormsMediaTestCase(SimpleTestCase):
     def test_absolute_url(self):

+ 54 - 16
tests/staticfiles_tests/test_management.py

@@ -9,7 +9,7 @@ from unittest import mock
 
 from admin_scripts.tests import AdminScriptTestCase
 
-from django.conf import settings
+from django.conf import STATICFILES_STORAGE_ALIAS, settings
 from django.contrib.staticfiles import storage
 from django.contrib.staticfiles.management.commands import collectstatic, runserver
 from django.core.exceptions import ImproperlyConfigured
@@ -141,16 +141,24 @@ class TestConfiguration(StaticFilesTestCase):
         try:
             storage.staticfiles_storage._wrapped = empty
             with self.settings(
-                STATICFILES_STORAGE=(
-                    "django.contrib.staticfiles.storage.StaticFilesStorage"
-                )
+                STORAGES={
+                    STATICFILES_STORAGE_ALIAS: {
+                        "BACKEND": (
+                            "django.contrib.staticfiles.storage.StaticFilesStorage"
+                        )
+                    }
+                }
             ):
                 command = collectstatic.Command()
                 self.assertTrue(command.is_local_storage())
 
             storage.staticfiles_storage._wrapped = empty
             with self.settings(
-                STATICFILES_STORAGE="staticfiles_tests.storage.DummyStorage"
+                STORAGES={
+                    STATICFILES_STORAGE_ALIAS: {
+                        "BACKEND": "staticfiles_tests.storage.DummyStorage"
+                    }
+                }
             ):
                 command = collectstatic.Command()
                 self.assertFalse(command.is_local_storage())
@@ -241,9 +249,13 @@ class TestCollectionVerbosity(CollectionTestCase):
         self.assertIn(self.copying_msg, output)
 
     @override_settings(
-        STATICFILES_STORAGE=(
-            "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
-        )
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": (
+                    "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+                )
+            },
+        }
     )
     def test_verbosity_1_with_post_process(self):
         stdout = StringIO()
@@ -251,9 +263,13 @@ class TestCollectionVerbosity(CollectionTestCase):
         self.assertNotIn(self.post_process_msg, stdout.getvalue())
 
     @override_settings(
-        STATICFILES_STORAGE=(
-            "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
-        )
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": (
+                    "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+                )
+            },
+        }
     )
     def test_verbosity_2_with_post_process(self):
         stdout = StringIO()
@@ -280,7 +296,11 @@ class TestCollectionClear(CollectionTestCase):
         super().run_collectstatic(clear=True)
 
     @override_settings(
-        STATICFILES_STORAGE="staticfiles_tests.storage.PathNotImplementedStorage"
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": "staticfiles_tests.storage.PathNotImplementedStorage"
+            },
+        }
     )
     def test_handle_path_notimplemented(self):
         self.run_collectstatic()
@@ -395,7 +415,11 @@ class TestCollectionDryRun(TestNoFilesCreated, CollectionTestCase):
 
 
 @override_settings(
-    STATICFILES_STORAGE="django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage"
+        },
+    }
 )
 class TestCollectionDryRunManifestStaticFilesStorage(TestCollectionDryRun):
     pass
@@ -518,7 +542,13 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
             self.assertNotIn(self.warning_string, output)
 
 
-@override_settings(STATICFILES_STORAGE="staticfiles_tests.storage.DummyStorage")
+@override_settings(
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.storage.DummyStorage"
+        },
+    }
+)
 class TestCollectionNonLocalStorage(TestNoFilesCreated, CollectionTestCase):
     """
     Tests for a Storage that implements get_modified_time() but not path()
@@ -540,7 +570,11 @@ class TestCollectionNonLocalStorage(TestNoFilesCreated, CollectionTestCase):
 
 class TestCollectionNeverCopyStorage(CollectionTestCase):
     @override_settings(
-        STATICFILES_STORAGE="staticfiles_tests.storage.NeverCopyRemoteStorage"
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": "staticfiles_tests.storage.NeverCopyRemoteStorage"
+            },
+        }
     )
     def test_skips_newer_files_in_remote_storage(self):
         """
@@ -607,7 +641,11 @@ class TestCollectionLinks(TestDefaults, CollectionTestCase):
         self.assertFalse(os.path.lexists(broken_symlink_path))
 
     @override_settings(
-        STATICFILES_STORAGE="staticfiles_tests.storage.PathNotImplementedStorage"
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": "staticfiles_tests.storage.PathNotImplementedStorage"
+            }
+        }
     )
     def test_no_remote_link(self):
         with self.assertRaisesMessage(

+ 42 - 8
tests/staticfiles_tests/test_storage.py

@@ -8,7 +8,7 @@ from io import StringIO
 from pathlib import Path
 from unittest import mock
 
-from django.conf import settings
+from django.conf import STATICFILES_STORAGE_ALIAS, settings
 from django.contrib.staticfiles import finders, storage
 from django.contrib.staticfiles.management.commands.collectstatic import (
     Command as CollectstaticCommand,
@@ -369,7 +369,13 @@ class TestHashedFiles:
         self.assertPostCondition()
 
 
-@override_settings(STATICFILES_STORAGE="staticfiles_tests.storage.ExtraPatternsStorage")
+@override_settings(
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.storage.ExtraPatternsStorage",
+        },
+    }
+)
 class TestExtraPatternsStorage(CollectionTestCase):
     def setUp(self):
         storage.staticfiles_storage.hashed_files.clear()  # avoid cache interference
@@ -399,7 +405,11 @@ class TestExtraPatternsStorage(CollectionTestCase):
 
 
 @override_settings(
-    STATICFILES_STORAGE="django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+        },
+    }
 )
 class TestCollectionManifestStorage(TestHashedFiles, CollectionTestCase):
     """
@@ -559,7 +569,13 @@ class TestCollectionManifestStorage(TestHashedFiles, CollectionTestCase):
         self.assertEqual(manifest_content, {"dummy.txt": "dummy.txt"})
 
 
-@override_settings(STATICFILES_STORAGE="staticfiles_tests.storage.NoneHashStorage")
+@override_settings(
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.storage.NoneHashStorage",
+        },
+    }
+)
 class TestCollectionNoneHashStorage(CollectionTestCase):
     hashed_file_path = hashed_file_path
 
@@ -569,7 +585,11 @@ class TestCollectionNoneHashStorage(CollectionTestCase):
 
 
 @override_settings(
-    STATICFILES_STORAGE="staticfiles_tests.storage.NoPostProcessReplacedPathStorage"
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.storage.NoPostProcessReplacedPathStorage",
+        },
+    }
 )
 class TestCollectionNoPostProcessReplacedPaths(CollectionTestCase):
     run_collectstatic_in_setUp = False
@@ -580,7 +600,13 @@ class TestCollectionNoPostProcessReplacedPaths(CollectionTestCase):
         self.assertIn("post-processed", stdout.getvalue())
 
 
-@override_settings(STATICFILES_STORAGE="staticfiles_tests.storage.SimpleStorage")
+@override_settings(
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "staticfiles_tests.storage.SimpleStorage",
+        },
+    }
+)
 class TestCollectionSimpleStorage(CollectionTestCase):
     hashed_file_path = hashed_file_path
 
@@ -733,7 +759,11 @@ class TestStaticFilePermissions(CollectionTestCase):
     @override_settings(
         FILE_UPLOAD_PERMISSIONS=0o655,
         FILE_UPLOAD_DIRECTORY_PERMISSIONS=0o765,
-        STATICFILES_STORAGE="staticfiles_tests.test_storage.CustomStaticFilesStorage",
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": "staticfiles_tests.test_storage.CustomStaticFilesStorage",
+            },
+        },
     )
     def test_collect_static_files_subclass_of_static_storage(self):
         call_command("collectstatic", **self.command_params)
@@ -753,7 +783,11 @@ class TestStaticFilePermissions(CollectionTestCase):
 
 
 @override_settings(
-    STATICFILES_STORAGE="django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+    STORAGES={
+        STATICFILES_STORAGE_ALIAS: {
+            "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
+        },
+    }
 )
 class TestCollectionHashedFilesCache(CollectionTestCase):
     """

+ 6 - 1
tests/staticfiles_tests/test_templatetags.py

@@ -1,3 +1,4 @@
+from django.conf import STATICFILES_STORAGE_ALIAS
 from django.test import override_settings
 
 from .cases import StaticFilesTestCase
@@ -12,7 +13,11 @@ class TestTemplateTag(StaticFilesTestCase):
         )
 
     @override_settings(
-        STATICFILES_STORAGE="staticfiles_tests.storage.QueryStringStorage"
+        STORAGES={
+            STATICFILES_STORAGE_ALIAS: {
+                "BACKEND": "staticfiles_tests.storage.QueryStringStorage"
+            },
+        }
     )
     def test_template_tag_escapes(self):
         """

+ 5 - 3
tests/test_utils/tests.py

@@ -5,7 +5,7 @@ import warnings
 from io import StringIO
 from unittest import mock
 
-from django.conf import settings
+from django.conf import STATICFILES_STORAGE_ALIAS, settings
 from django.contrib.staticfiles.finders import get_finder, get_finders
 from django.contrib.staticfiles.storage import staticfiles_storage
 from django.core.exceptions import ImproperlyConfigured
@@ -2106,12 +2106,14 @@ class OverrideSettingsTests(SimpleTestCase):
 
     def test_override_staticfiles_storage(self):
         """
-        Overriding the STATICFILES_STORAGE setting should be reflected in
+        Overriding the STORAGES setting should be reflected in
         the value of django.contrib.staticfiles.storage.staticfiles_storage.
         """
         new_class = "ManifestStaticFilesStorage"
         new_storage = "django.contrib.staticfiles.storage." + new_class
-        with self.settings(STATICFILES_STORAGE=new_storage):
+        with self.settings(
+            STORAGES={STATICFILES_STORAGE_ALIAS: {"BACKEND": new_storage}}
+        ):
             self.assertEqual(staticfiles_storage.__class__.__name__, new_class)
 
     def test_override_staticfiles_finders(self):