1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +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
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)

View File

@ -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/"

View File

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

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.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()

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.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):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
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::

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
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!">

View File

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

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

View File

@ -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
================================= ========================
DEFAULT_FILE_STORAGE, STATICFILES_STORAGE, STATIC_ROOT, STATIC_URL, STORAGES Storages configuration
============================================================================ ========================
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 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."

View File

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

View File

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

View File

@ -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=(
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=(
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=(
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(

View File

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

View File

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

View File

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