-
Notifications
You must be signed in to change notification settings - Fork 4.1k
feat!: upgrade code and fix get_storage_class ( compatibility django42 and django52) #36628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Replaced usage of `get_storage_class`, which was deprecated in Django 4.2 and removed in 5.1, with `import_string` to support dynamic storage class loading.
storage_class_path = config.get('class') | ||
storage_class = import_string(storage_class_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure if this case could ever occur but if the contents of storage_class_path are incorrect, there could be an error which we should catch e.g
try: storage_class = import_string(storage_class_path) except ImportError as e: raise ImproperlyConfigured( f"Could not import storage class '{storage_class_path}': {e}" )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! |
storage_class_path = config.get('class') | ||
storage_class = import_string(storage_class_path) | ||
return storage_class(**config.get('options', {})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are not we using the below one?
from django.core.files.storage import storages
storage_class = storages(config.get('class'))
return storage_class(**config.get('options', {}))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2ffa43e
to
03e8c83
Compare
@feanil Please review |
if not storage_class_path: | ||
storage_class_path = ( | ||
getattr(settings, 'DEFAULT_FILE_STORAGE', None) or | ||
getattr(settings, 'STORAGES', {}).get('default', {}).get('BACKEND') or | ||
'django.core.files.storage.FileSystemStorage' | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before we fallback to the default storage class, I think we should also have a named storage class in the STORAGES
dictionary. Maybe named profile_images
?
This way, operators could migrate to defining their various storages config via the new STORAGES
config and we can eventually deprecate the old configuration settings.
@feanil I have verified on django42 this solution will not work. These settings cannot declare together.
These cannot declared together. It raises error
Django code reference Right now |
@feanil its ready for final review. |
@feanil its ready. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the profile image storage helper to support both the existing PROFILE_IMAGE_BACKEND
setting and the new Django 5+ STORAGES
configuration, and adds tests in test_views.py
to validate each fallback path.
- Migrate from
get_storage_class
toimport_string
and explicit resolution order for storage backends. - Introduce support for the new
STORAGES
setting (withprofile_image
anddefault
keys) before falling back toDEFAULT_FILE_STORAGE
orFileSystemStorage
. - Add comprehensive tests in
test_views.py
to verify default, parameterized, STORAGES-based, and hardcoded fallback behaviors.
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
openedx/core/djangoapps/user_api/accounts/tests/test_views.py | New tests covering get_profile_image_storage under various PROFILE_IMAGE_BACKEND and STORAGES scenarios |
openedx/core/djangoapps/user_api/accounts/image_helpers.py | Refactored get_profile_image_storage to use import_string , support Django 5+ STORAGES , and drop get_storage_class |
Comments suppressed due to low confidence (1)
openedx/core/djangoapps/user_api/accounts/tests/test_views.py:1173
- [nitpick] Test method names are inconsistent: the first test is
test_profile_image_backend
, but subsequent tests usetest_profile_backend_*
. For clarity, rename them totest_profile_image_backend_with_params
,test_profile_image_backend_without_backend
, etc.
@override_settings(PROFILE_IMAGE_BACKEND={
@@ -8,10 +8,11 @@ | |||
from django.conf import settings | |||
from django.contrib.staticfiles.storage import staticfiles_storage | |||
from django.core.exceptions import ObjectDoesNotExist | |||
from django.core.files.storage import get_storage_class | |||
from django.core.files.storage import storages |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Importing storages
directly will break on Django versions before 5.0, where this attribute doesn't exist. Wrap this import in a try/except ImportError
and fall back to a compatible approach (e.g., using import_string
or the legacy get_storage_class
) for Django<5.0.
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is wrong, django had the storages
import available in 4.2, it just drops the get_storage_class function in 5.0 which is what we're trying to fix here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good, just one more change and then I think it's good to merge.
FYI, I've added a note to the Ulmo release page for operators so they know about the new storage class name and can switch to it after Ulmo lands so we can remove support for the conversion from the old way to the new way.
@awais786 once you've made the final change, I don't need to re-review it if it looks good to you and we have test coverage testing the priority order is working correctly.
|
||
1. If the `PROFILE_IMAGE_BACKEND` setting is defined and includes a `'class'` key, | ||
it uses the specified storage backend and options. | ||
2. If not, it checks the Django 5+ `STORAGES` setting for a named storage called |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be the highest priority option, we should also make the newest way to do things the highest priority, falling back to the older ways for compatibility. This makes it easier to read and also easier to cleanup in the future when we want to drop all the old ways of doing this.
Sandbox deployment successful 🚀 |
Sandbox deployment failed 💥 |
Sandbox deployment failed 💥 |
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
2U Release Notice: This PR has been deployed to the edX production environment. |
1 similar comment
2U Release Notice: This PR has been deployed to the edX production environment. |
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
2U Release Notice: This PR has been deployed to the edX production environment. |
#36740
Fixing breaking change for django52.
https://app.pr-36628-139931.sandboxes.opencraft.hosting/profile/u/openedx
opened/openedx