1
0
mirror of https://github.com/django/django.git synced 2025-08-11 04:19:11 +00:00

Refs #26029 -- Deprecated DEFAULT_FILE_STORAGE and STATICFILES_STORAGE settings.

This commit is contained in:
Jarosław Wygoda 2022-09-11 17:33:47 +02:00 committed by Mariusz Felisiak
parent 1ec3f0961f
commit 32940d390a
24 changed files with 542 additions and 90 deletions

View File

@ -16,10 +16,12 @@ from pathlib import Path
import django import django
from django.conf import global_settings from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured 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 from django.utils.functional import LazyObject, empty
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
DEFAULT_STORAGE_ALIAS = "default"
STATICFILES_STORAGE_ALIAS = "staticfiles"
# RemovedInDjango50Warning # RemovedInDjango50Warning
USE_DEPRECATED_PYTZ_DEPRECATED_MSG = ( USE_DEPRECATED_PYTZ_DEPRECATED_MSG = (
@ -39,6 +41,14 @@ CSRF_COOKIE_MASKED_DEPRECATED_MSG = (
"it will be removed in Django 5.0." "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): class SettingsReference(str):
""" """
@ -177,6 +187,22 @@ class LazySettings(LazyObject):
# paths. # paths.
return self.__getattr__("USE_L10N") 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: class Settings:
def __init__(self, settings_module): def __init__(self, settings_module):
@ -240,6 +266,20 @@ class Settings:
if self.is_overridden("USE_L10N"): if self.is_overridden("USE_L10N"):
warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning) 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): def is_overridden(self, setting):
return setting in self._explicit_settings return setting in self._explicit_settings
@ -276,9 +316,29 @@ class UserSettingsHolder:
warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning) warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
if name == "CSRF_COOKIE_MASKED": if name == "CSRF_COOKIE_MASKED":
warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning) 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) super().__setattr__(name, value)
if name == "USE_DEPRECATED_PYTZ": if name == "USE_DEPRECATED_PYTZ":
warnings.warn(USE_DEPRECATED_PYTZ_DEPRECATED_MSG, RemovedInDjango50Warning) 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): def __delattr__(self, name):
self._deleted.add(name) self._deleted.add(name)

View File

@ -280,7 +280,14 @@ SECRET_KEY_FALLBACKS = []
# Default file storage mechanism that holds media. # Default file storage mechanism that holds media.
DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage" 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. # Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/var/www/example.com/media/" # Example: "/var/www/example.com/media/"

View File

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

View File

@ -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.functional import LazyObject
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
@ -19,14 +22,20 @@ __all__ = (
"storages", "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): 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) return import_string(import_path or settings.DEFAULT_FILE_STORAGE)
class DefaultStorage(LazyObject): class DefaultStorage(LazyObject):
def _setup(self): def _setup(self):
self._wrapped = get_storage_class()() self._wrapped = storages[DEFAULT_STORAGE_ALIAS]
storages = StorageHandler() storages = StorageHandler()

View File

@ -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.core.exceptions import ImproperlyConfigured
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
@ -19,6 +19,15 @@ class StorageHandler:
def backends(self): def backends(self):
if self._backends is None: if self._backends is None:
self._backends = settings.STORAGES.copy() 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 return self._backends
def __getitem__(self, alias): def __getitem__(self, alias):

View File

@ -13,6 +13,7 @@ from django.dispatch import Signal, receiver
from django.utils import timezone from django.utils import timezone
from django.utils.formats import FORMAT_SETTINGS, reset_format_cache from django.utils.formats import FORMAT_SETTINGS, reset_format_cache
from django.utils.functional import empty from django.utils.functional import empty
from django.utils.module_loading import import_string
template_rendered = Signal() template_rendered = Signal()
@ -113,7 +114,8 @@ def reset_template_engines(*, setting, **kwargs):
@receiver(setting_changed) @receiver(setting_changed)
def storages_changed(*, setting, **kwargs): 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 ( if setting in (
"STORAGES", "STORAGES",
@ -127,6 +129,9 @@ def storages_changed(*, setting, **kwargs):
storages._backends = None storages._backends = None
storages._storages = {} storages._storages = {}
default_storage._wrapped = empty
staticfiles_storage._wrapped = empty
@receiver(setting_changed) @receiver(setting_changed)
def clear_serializers_cache(*, setting, **kwargs): def clear_serializers_cache(*, setting, **kwargs):
@ -156,11 +161,18 @@ def localize_settings_changed(*, setting, **kwargs):
reset_format_cache() reset_format_cache()
# RemovedInDjango51Warning.
@receiver(setting_changed) @receiver(setting_changed)
def file_storage_changed(*, setting, **kwargs): def file_storage_changed(*, setting, **kwargs):
if setting == "DEFAULT_FILE_STORAGE": 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 default_storage._wrapped = empty
@ -195,6 +207,17 @@ def static_storage_changed(*, setting, **kwargs):
staticfiles_storage._wrapped = empty 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) @receiver(setting_changed)
def static_finders_changed(*, setting, **kwargs): def static_finders_changed(*, setting, **kwargs):

View File

@ -15,8 +15,8 @@ Serving static files in production
The basic outline of putting static files into production consists of two The basic outline of putting static files into production consists of two
steps: run the :djadmin:`collectstatic` command when static files change, then steps: run the :djadmin:`collectstatic` command when static files change, then
arrange for the collected static files directory (:setting:`STATIC_ROOT`) to be arrange for the collected static files directory (:setting:`STATIC_ROOT`) to be
moved to the static file server and served. Depending on moved to the static file server and served. Depending the ``staticfiles``
:setting:`STATICFILES_STORAGE`, files may need to be moved to a new location :setting:`STORAGES` alias, files may need to be moved to a new location
manually or the :func:`post_process manually or the :func:`post_process
<django.contrib.staticfiles.storage.StaticFilesStorage.post_process>` method of <django.contrib.staticfiles.storage.StaticFilesStorage.post_process>` method of
the ``Storage`` class might take care of that. 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>` 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 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 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 For example, if you've written an S3 storage backend in
``myproject.storage.S3Storage`` you could use it with:: ``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 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 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 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 For details on how you'd write one of these backends, see
:doc:`/howto/custom-file-storage`. There are 3rd party apps available that :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 point is the `overview at djangopackages.org
<https://djangopackages.org/grids/g/storage-backends/>`_. <https://djangopackages.org/grids/g/storage-backends/>`_.
.. versionchanged:: 4.2
The :setting:`STORAGES` setting was added.
Learn more Learn more
========== ==========

View File

@ -19,7 +19,8 @@ Configuring static files
STATIC_URL = 'static/' STATIC_URL = 'static/'
#. In your templates, use the :ttag:`static` template tag to build the URL for #. 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: .. _staticfiles-in-templates:

View File

@ -45,6 +45,12 @@ details on these changes.
* Support for passing positional arguments to ``Signer`` and * Support for passing positional arguments to ``Signer`` and
``TimestampSigner`` will be removed. ``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: .. _deprecation-removed-in-5.0:
5.0 5.0

View File

@ -60,11 +60,12 @@ specified by the :setting:`INSTALLED_APPS` setting.
The :djadmin:`collectstatic` management command calls the The :djadmin:`collectstatic` management command calls the
:meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process` :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
method of the :setting:`STATICFILES_STORAGE` after each run and passes method of the ``staticfiles`` storage backend from :setting:`STORAGES` after
a list of paths that have been found by the management command. It also each run and passes a list of paths that have been found by the management
receives all command line options of :djadmin:`collectstatic`. This is used command. It also receives all command line options of :djadmin:`collectstatic`.
by the :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` This is used by the
by default. :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` by
default.
By default, collected files receive permissions from By default, collected files receive permissions from
:setting:`FILE_UPLOAD_PERMISSIONS` and collected directories receive permissions :setting:`FILE_UPLOAD_PERMISSIONS` and collected directories receive permissions
@ -82,7 +83,7 @@ respectively. For example::
kwargs['directory_permissions_mode'] = 0o760 kwargs['directory_permissions_mode'] = 0o760
super().__init__(*args, **kwargs) 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'``. ``'path.to.MyStaticFilesStorage'``.
Some commonly used options are: Some commonly used options are:
@ -113,7 +114,8 @@ Some commonly used options are:
Don't call the Don't call the
:meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process` :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 .. 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 To enable the ``ManifestStaticFilesStorage`` you have to make sure the
following requirements are met: 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'`` ``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'``
* the :setting:`DEBUG` setting is set to ``False`` * the :setting:`DEBUG` setting is set to ``False``
* you've collected all your static files by using the * 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 Due to the requirement of running :djadmin:`collectstatic`, this storage
typically shouldn't be used when running tests as ``collectstatic`` isn't run 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 as part of the normal test setup. During testing, ensure that ``staticfiles``
:setting:`STATICFILES_STORAGE` setting is set to something else like storage backend in the :setting:`STORAGES` setting is set to something else
``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default). like ``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default).
.. method:: storage.ManifestStaticFilesStorage.file_hash(name, content=None) .. 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 - The builtin template tag :ttag:`static` which takes a path and urljoins it
with the static prefix :setting:`STATIC_URL`. If with the static prefix :setting:`STATIC_URL`. If
``django.contrib.staticfiles`` is installed, the tag uses the ``url()`` ``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 - The builtin template tag :ttag:`get_static_prefix` which populates a
template variable with the static prefix :setting:`STATIC_URL` to be 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 - The similar template tag :ttag:`get_media_prefix` which works like
:ttag:`get_static_prefix` but uses :setting:`MEDIA_URL`. :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: .. _staticfiles-development-view:
Static file development view Static file development view

View File

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

View File

@ -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 Default file storage class to be used for any file-related operations that don't
specify a particular storage system. See :doc:`/topics/files`. 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 .. setting:: DEFAULT_FROM_EMAIL
``DEFAULT_FROM_EMAIL`` ``DEFAULT_FROM_EMAIL``
@ -2615,13 +2621,28 @@ See also the :doc:`/ref/checks` documentation.
Default:: 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. 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 It is a nested dictionary whose contents map a storage alias to a dictionary
containing the options for an individual storage. 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 The following is an example ``settings.py`` snippet defining a custom file
storage called ``example``:: storage called ``example``::
@ -3598,10 +3619,16 @@ The file storage engine to use when collecting static files with the
:djadmin:`collectstatic` management command. :djadmin:`collectstatic` management command.
A ready-to-use instance of the storage backend defined in this setting 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`. 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 .. setting:: STATICFILES_FINDERS
``STATICFILES_FINDERS`` ``STATICFILES_FINDERS``
@ -3627,8 +3654,8 @@ used.
One finder is disabled by default: One finder is disabled by default:
``django.contrib.staticfiles.finders.DefaultStorageFinder``. If added to ``django.contrib.staticfiles.finders.DefaultStorageFinder``. If added to
your :setting:`STATICFILES_FINDERS` setting, it will look for static files in your :setting:`STATICFILES_FINDERS` setting, it will look for static files in
the default file storage as defined by the :setting:`DEFAULT_FILE_STORAGE` the default file storage as defined by the ``default`` key in the
setting. :setting:`STORAGES` setting.
.. note:: .. note::

View File

@ -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 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` 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 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 %} {% load static %}
<img src="{% static 'images/hi.jpg' %}" alt="Hi!"> <img src="{% static 'images/hi.jpg' %}" alt="Hi!">

View File

@ -95,7 +95,12 @@ Custom file storages
-------------------- --------------------
The new :setting:`STORAGES` setting allows configuring multiple custom file 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 Minor features
-------------- --------------
@ -674,3 +679,11 @@ Miscellaneous
* Passing positional arguments to ``Signer`` and ``TimestampSigner`` is * Passing positional arguments to ``Signer`` and ``TimestampSigner`` is
deprecated in favor of keyword-only arguments. 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.

View File

@ -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 to a file storage system. This is the object that actually understands things
like file systems, opening and reading files, etc. like file systems, opening and reading files, etc.
Django's default file storage is given by the :setting:`DEFAULT_FILE_STORAGE` Django's default file storage is
setting; if you don't explicitly provide a storage system, this is the one that ``'``:class:`django.core.files.storage.FileSystemStorage`\ ``'``. If you don't
will be used. 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 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 :doc:`/howto/custom-file-storage` for information on writing your own file

View File

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

View File

@ -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)

View File

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

View File

@ -9,6 +9,7 @@ from io import BytesIO, StringIO
from unittest import mock from unittest import mock
from urllib.parse import quote from urllib.parse import quote
from django.conf import DEFAULT_STORAGE_ALIAS
from django.core.exceptions import SuspiciousFileOperation from django.core.exceptions import SuspiciousFileOperation
from django.core.files import temp as tempfile from django.core.files import temp as tempfile
from django.core.files.storage import default_storage 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()." sys.platform == "win32", "Python on Windows doesn't have working os.chmod()."
) )
@override_settings( @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): def test_readonly_root(self):
"""Permission errors are not swallowed""" """Permission errors are not swallowed"""

View File

@ -1,5 +1,6 @@
from urllib.parse import urljoin from urllib.parse import urljoin
from django.conf import STATICFILES_STORAGE_ALIAS
from django.contrib.staticfiles import storage from django.contrib.staticfiles import storage
from django.forms import Media from django.forms import Media
from django.templatetags.static import static from django.templatetags.static import static
@ -12,9 +13,13 @@ class StaticTestStorage(storage.StaticFilesStorage):
@override_settings( @override_settings(
STATIC_URL="http://media.example.com/static/",
INSTALLED_APPS=("django.contrib.staticfiles",), 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): class StaticFilesFormsMediaTestCase(SimpleTestCase):
def test_absolute_url(self): def test_absolute_url(self):

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import warnings
from io import StringIO from io import StringIO
from unittest import mock 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.finders import get_finder, get_finders
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
@ -2106,12 +2106,14 @@ class OverrideSettingsTests(SimpleTestCase):
def test_override_staticfiles_storage(self): 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. the value of django.contrib.staticfiles.storage.staticfiles_storage.
""" """
new_class = "ManifestStaticFilesStorage" new_class = "ManifestStaticFilesStorage"
new_storage = "django.contrib.staticfiles.storage." + new_class 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) self.assertEqual(staticfiles_storage.__class__.__name__, new_class)
def test_override_staticfiles_finders(self): def test_override_staticfiles_finders(self):