Repository: cookiecutter/cookiecutter-django

Issue:
Migrate the media & static settings to the new unified `STORAGES`
## Description

Django 4.2 introduced a unified [`STORAGES` setting](https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-STORAGES) which unifies static & media setup and simplifies adding a custom storage that might be required by an application (e.g. private media).

## Rationale

The [`DEFAULT_FILE_STORAGE`](https://docs.djangoproject.com/en/4.2/ref/settings/#default-file-storage) and [`STATICFILES_STORAGE`](https://docs.djangoproject.com/en/4.2/ref/settings/#staticfiles-storage) settings are now both deprecated and we should migrate to the new setting before Django 5.1


Discussion:
Hello @browniebroke ,
Currently I am working on it and it passed all the [Templates Test Suit](https://github.com/cookiecutter/cookiecutter-django/blob/f10253a3b3645d9b2629bc1cd8cecd1cefd1467f/CONTRIBUTING.md#run-the-templates-test-suite). But [Generate project tests](https://github.com/cookiecutter/cookiecutter-django/blob/f10253a3b3645d9b2629bc1cd8cecd1cefd1467f/CONTRIBUTING.md#run-the-generated-project-tests) fails with `django.db.utils.OperationalError: connection is bad: No such file or directory` error message. (using `test_bare.sh`)
Do we need local database running? where am I wrong?

Resolving patch:
diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py
--- a/{{cookiecutter.project_slug}}/config/settings/production.py
+++ b/{{cookiecutter.project_slug}}/config/settings/production.py
@@ -103,35 +103,52 @@
 {% endif -%}
 
 {% if cookiecutter.cloud_provider != 'None' or cookiecutter.use_whitenoise == 'y' -%}
-# STATIC
+# STATIC & MEDIA
 # ------------------------
-{% endif -%}
-{% if cookiecutter.use_whitenoise == 'y' -%}
-STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
-{% elif cookiecutter.cloud_provider == 'AWS' -%}
-STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticS3Storage"
-COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
-STATIC_URL = f"https://{aws_s3_domain}/static/"
-{% elif cookiecutter.cloud_provider == 'GCP' -%}
-STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticGoogleCloudStorage"
-COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
-STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
-{% elif cookiecutter.cloud_provider == 'Azure' -%}
-STATICFILES_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.StaticAzureStorage"
-STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/"
-{% endif -%}
+STORAGES = {
+{%- if cookiecutter.use_whitenoise == 'y' %}
+    "default": {
+        "BACKEND": "django.core.files.storage.FileSystemStorage",
+    },
+    "staticfiles": {
+        "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
+    },
+{%- elif cookiecutter.cloud_provider == 'AWS' %}
+    "default": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.MediaS3Storage",
+    },
+    "staticfiles": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.StaticS3Storage",
+    },
+{%- elif cookiecutter.cloud_provider == 'GCP' %}
+    "default": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.MediaGoogleCloudStorage",
+    },
+    "staticfiles": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.StaticGoogleCloudStorage",
+    },
+{%- elif cookiecutter.cloud_provider == 'Azure' %}
+    "default": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.MediaAzureStorage",
+    },
+    "staticfiles": {
+        "BACKEND": "{{cookiecutter.project_slug}}.utils.storages.StaticAzureStorage",
+    },
+{%- endif %}
+}
+{%- endif %}
 
-# MEDIA
-# ------------------------------------------------------------------------------
 {%- if cookiecutter.cloud_provider == 'AWS' %}
-DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaS3Storage"
 MEDIA_URL = f"https://{aws_s3_domain}/media/"
+COLLECTFAST_STRATEGY = "collectfast.strategies.boto3.Boto3Strategy"
+STATIC_URL = f"https://{aws_s3_domain}/static/"
 {%- elif cookiecutter.cloud_provider == 'GCP' %}
-DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaGoogleCloudStorage"
 MEDIA_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/media/"
+COLLECTFAST_STRATEGY = "collectfast.strategies.gcloud.GoogleCloudStrategy"
+STATIC_URL = f"https://storage.googleapis.com/{GS_BUCKET_NAME}/static/"
 {%- elif cookiecutter.cloud_provider == 'Azure' %}
-DEFAULT_FILE_STORAGE = "{{cookiecutter.project_slug}}.utils.storages.MediaAzureStorage"
 MEDIA_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/media/"
+STATIC_URL = f"https://{AZURE_ACCOUNT_NAME}.blob.core.windows.net/static/"
 {%- endif %}
 
 # EMAIL
@@ -230,7 +247,7 @@
 COMPRESS_STORAGE = "compressor.storage.GzipCompressorFileStorage"
 {%- elif cookiecutter.cloud_provider in ('AWS', 'GCP', 'Azure') and cookiecutter.use_whitenoise == 'n' %}
 # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_STORAGE
-COMPRESS_STORAGE = STATICFILES_STORAGE
+COMPRESS_STORAGE = STORAGES["staticfiles"]["BACKEND"]
 {%- endif %}
 # https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_URL
 COMPRESS_URL = STATIC_URL{% if cookiecutter.use_whitenoise == 'y' or cookiecutter.cloud_provider == 'None' %}  # noqa: F405{% endif %}


Test patch: