Skip to content

Conversation

@mubbsharanwar
Copy link
Contributor

@mubbsharanwar mubbsharanwar commented Aug 25, 2025

Description

Depreciate STATICFILES_STORAGE and DEFAULT_FILE_STORAGE, and use STORAGE to upgrade edx-platform to Django 5.2

@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch 2 times, most recently from bfc5722 to 029594a Compare August 25, 2025 09:47
@deborahgu
Copy link
Member

is this different from #2828 which has a pending question on it?

@mubbsharanwar mubbsharanwar requested a review from awais786 August 25, 2025 13:41
@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch 6 times, most recently from d14cbac to 7cd09bf Compare August 26, 2025 14:45
@awais786
Copy link
Contributor

is this different from #2828 which has a pending question on it?

Yes this is actual one

@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch 3 times, most recently from 9733674 to 10baf35 Compare August 27, 2025 08:50
@awais786
Copy link
Contributor

@wgu-ram-chandra Please review this PR.

@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch from 10baf35 to 29560aa Compare September 2, 2025 06:06
…FILES_STORAGE

Depriciate STATICFILES_STORAGE and DEFAULT_FILE_STORAGE, and use STORAGE in Django 5.2
@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch from 29560aa to 7ab9ce3 Compare September 2, 2025 06:10
@mubbsharanwar mubbsharanwar changed the title chore: use Django 5.2 STORAGES fix: Django52 use STORAGES instead of DEFAULT_FILE_STORAGE and STATICFILES_STORAGE Sep 2, 2025
@deborahgu deborahgu moved this to Todo in Aperture-Maintained Sep 2, 2025
@deborahgu deborahgu added the waiting for eng review PR is ready for review. Review and merge it, or suggest changes. label Sep 2, 2025
@deborahgu
Copy link
Member

this is awaiting review from @wgu-ram-chandra, but also, I assume that this one should not be merged until all of the pending requests have been resolved on the related PR openedx/edx-platform#37002, because any related issues should presumably be addressed here as well.

@awais786
Copy link
Contributor

awais786 commented Sep 2, 2025

@deborahgu Yes we are following that as well

@wgu-ram-chandra
Copy link

wgu-ram-chandra commented Sep 2, 2025

Hi @awais786 @deborahgu, sorry for the delay. I'll review it today!

Copy link

@wgu-ram-chandra wgu-ram-chandra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mubbsharanwar Thanks for the PR! I’ve left a few comments, once those are addressed, I’ll be happy to take another look.

EMAIL_FILE_PATH = "/tmp/credentials-emails"

DEFAULT_FILE_STORAGE = os.environ.get("DEFAULT_FILE_STORAGE", "django.core.files.storage.FileSystemStorage")
STORAGES["default"]["BACKEND"] = os.environ.get(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.environ.get() expects an environment variable name, but the current code passes the backend value instead. This ends up looking for an env var like "django.core.files.storage.FileSystemStorage", which won’t exist, so it always falls back to the default and the override never takes effect.

We could assign django.core.files.storage.FileSystemStorage directly, or alternatively read from DEFAULT_FILE_STORAGE and assign that to maintain backward compatibility.

MEDIA_URL = os.environ.get("MEDIA_URL", "/media/")

STATICFILES_STORAGE = os.environ.get("STATICFILES_STORAGE", "django.contrib.staticfiles.storage.StaticFilesStorage")
STORAGES["staticfiles"]["BACKEND"] = "django.contrib.staticfiles.storage.StaticFilesStorage"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here! We could assign django.contrib.staticfiles.storage.StaticFilesStorage directly, or alternatively read from STATICFILES_STORAGE and assign for backward compatibility.


if "DEFAULT_FILE_STORAGE" in config_from_yaml:
STORAGES["default"] = {"BACKEND": config_from_yaml.pop("DEFAULT_FILE_STORAGE")}
vars().update(STORAGES)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using vars().update(STORAGES) can be risky because it flattens nested dictionaries into module-level variables like default and staticfiles, which is undesirable. It’s preferable to update the STORAGES dictionary directly rather than modifying vars().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mubbsharanwar it looks like this is still unaddressed.


vars().update(config_from_yaml)

if "DEFAULT_FILE_STORAGE" in FILE_STORAGE_BACKEND:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, it’s not obvious what structure FILE_STORAGE_BACKEND takes, it’s initialized as {} and later populated from CREDENTIALS_CFG. The if "DEFAULT_FILE_STORAGE" logic seems to assume it’s a flat dict with backend paths as values. Could you confirm whether that assumption is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that assumption is correct. DEFAULT_FILE_STORAGE is a flat dict.

# Local Directories
TEST_ROOT = path("test_root")
DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage"
STORAGES["default"]["BACKEND"] = os.environ.get(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as noted above in credentials/settings/devstack.py, this also applies to the old keys here.

@mubbsharanwar mubbsharanwar force-pushed the mubbsharanwar/upgrade-storages branch 2 times, most recently from c919ce7 to 54e6d0f Compare September 4, 2025 06:57
@kdmccormick
Copy link
Member

Could you get review from a maintainer instead?

@awais786
Copy link
Contributor

@deborahgu Please review this PR.

@feanil feanil requested review from a team September 12, 2025 14:38
@awais786
Copy link
Contributor

awais786 commented Sep 19, 2025

@feanil This is final PR with default django52 for credentials. We will merge after 2844.

@awais786
Copy link
Contributor

@deborahgu Please wait let me verify one thing.

@awais786
Copy link
Contributor

awais786 commented Sep 22, 2025

@deborahgu I just verified using this yaml

FILE_STORAGE_BACKEND:
  AWS_S3_OBJECT_PARAMETERS:
     CacheControl: max-age=31536000
  AWS_QUERYSTRING_AUTH: false
  AWS_QUERYSTRING_EXPIRE: false
  AWS_S3_CUSTOM_DOMAIN: stage.edx-cdn.org
  AWS_STORAGE_BUCKET_NAME: stage-edx
  DEFAULT_FILE_STORAGE: storages.backends.s3boto3.S3Boto3Storage
  MEDIA_ROOT: media
  MEDIA_URL: https://stage.edx-cdn.org/media/

So the django shell showing following output

>>> from django.conf import settings
>>> settings.STORAGES
{
'default': {'BACKEND': 'django.core.files.storage.FileSystemStorage'}, 
'staticfiles': {'BACKEND': 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'}
}
>>> settings.AWS_STORAGE_BUCKET_NAME
'stage-edx'
>>> settings.FILE_STORAGE_BACKEND
{'AWS_S3_OBJECT_PARAMETERS': 
{'CacheControl': 'max-age=31536000'}, 'AWS_QUERYSTRING_AUTH': False,
 'AWS_QUERYSTRING_EXPIRE': False, 
'AWS_S3_CUSTOM_DOMAIN': 'stage.edx-cdn.org',
 'AWS_STORAGE_BUCKET_NAME': 'stage-edx', 'MEDIA_ROOT': 'media',
 'MEDIA_URL': 'https://stage.edx-cdn.org/media/', 
'STORAGES': {'default': {'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage'}}}

Observation:

FILE_STORAGE_BACKEND contains the correct S3 configuration.

AWS_STORAGE_BUCKET_NAME is correctly set.

wrong behaviour
However, settings.STORAGES is still pointing to the default local file system instead of S3.

This is the root cause.

FILE_STORAGE_BACKEND.update(
      {
          "STORAGES": {
              "default": {"BACKEND": default_file_storage},
          }
      }
  )

@awais786
Copy link
Contributor

awais786 commented Sep 22, 2025

I don't have the domain knowledge but you can comment or test this PR as it is. If purpose is only to set FILE_STORAGE_BACKEND then its fine.


if "DEFAULT_FILE_STORAGE" in config_from_yaml:
STORAGES["default"] = {"BACKEND": config_from_yaml.pop("DEFAULT_FILE_STORAGE")}
vars().update(STORAGES)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mubbsharanwar it looks like this is still unaddressed.

vars().update(FILE_STORAGE_BACKEND)
if "DEFAULT_FILE_STORAGE" in FILE_STORAGE_BACKEND:
default_file_storage = FILE_STORAGE_BACKEND.pop("DEFAULT_FILE_STORAGE")
vars().update(FILE_STORAGE_BACKEND)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mubbsharanwar I think the bug is here. By running this vars().update(FILE_STORAGE_BACKEND) won't this will take the keys and values inside that dict and drop it at the top level of the settings dict? Is that the intention?

@deborahgu it looks like FILE_STORAGE_BACKEND is not a django notion but something we may have invented in our settings. Is this being used in credentials settings? How is it structured? I don't see any references to it in the code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@feanil I’ll fix it now; I just needed some clarification on the expected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@feanil I think I got the issue. I will fix both the PRs in credentials and disco.

Copy link
Contributor

@awais786 awais786 Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sample yaml

FILE_STORAGE_BACKEND
  AWS_STORAGE_BUCKET_NAME: stage-edx-catalog
  DEFAULT_FILE_STORAGE: storages.backends.s3boto3.S3Boto3Storage1234

All the keys from FILE_STORAGE_BACKEND are promoted to the root-level Django settings.
As soon as DEFAULT_FILE_STORAGE is set, Django automatically updates the STORAGES dict to reflect it.

IN django==4.2.24 you see this.

>>> from django.conf import settings
>>> settings.STORAGES
{'default': {'BACKEND': 'storages.backends.s3boto3.S3Boto3Storage1234'}, 'staticfiles': {'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage'}}
>>> settings.DEFAULT_FILE_STORAGE
'storages.backends.s3boto3.S3Boto3Storage1234'

So, setting DEFAULT_FILE_STORAGE directly ensures both DEFAULT_FILE_STORAGE and STORAGES['default'] stay in sync.

But for django52 we need to do this explicitly. So code is working due the root values set in production.

@awais786
Copy link
Contributor

@feanil @deborahgu Please review now.

Comment on lines 484 to 486
"STORAGES": {
"default": {"BACKEND": STORAGES["default"]["BACKEND"]},
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"STORAGES": {
"default": {"BACKEND": STORAGES["default"]["BACKEND"]},
},
"STORAGES": STORAGES

Comment on lines 46 to 53
STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to redefine STORAGES, its coming from base.py

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = "/tmp/credentials-emails"

DEFAULT_FILE_STORAGE = os.environ.get("DEFAULT_FILE_STORAGE", "django.core.files.storage.FileSystemStorage")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultfile_storage = os.environ.get("DEFAULT_FILE_STORAGE", "django.core.files.storage.FileSystemStorage")

if defaultfile_storage:
    STORAGES["default"]["BACKEND"] = defaultfile_storage

},
}

STATICFILES_STORAGE = os.environ.get("STATICFILES_STORAGE", "django.contrib.staticfiles.storage.StaticFilesStorage")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

staticfiles_storage = os.environ.get('STATICFILES_STORAGE', 'django.contrib.staticfiles.storage.StaticFilesStorage')

if staticfiles_storage:
    STORAGES["staticfiles"]["BACKEND"] = staticfiles_storage

Comment on lines 38 to 47

STORAGES = {
"default": {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to redefine the STORAGES

@awais786
Copy link
Contributor

@feanil its ready now.

@feanil
Copy link
Contributor

feanil commented Sep 26, 2025

Looks good, I'll do a final review and merge on Monday.

@awais786
Copy link
Contributor

awais786 commented Sep 29, 2025

For tracking purpose.

openedx/public-engineering#419

Don't set defaults when that are the same as the defaults from base.py setting them in multiple places could lead to confusion and bugs in the future.
@feanil feanil merged commit 53d1a60 into openedx:master Sep 29, 2025
10 checks passed
@github-project-automation github-project-automation bot moved this from Todo to Done in Aperture-Maintained Sep 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting for eng review PR is ready for review. Review and merge it, or suggest changes.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

7 participants