From 329b3fecfba19cd6ce20cddd0957f5055205cafb Mon Sep 17 00:00:00 2001 From: Peter Pfeufer Date: Sat, 31 May 2025 23:59:03 +0200 Subject: [PATCH] [ADD] Custom Static Files Storage Class --- allianceauth/framework/staticfiles/storage.py | 87 +++++++++++++++++++ .../project_name/settings/base.py | 9 ++ 2 files changed, 96 insertions(+) create mode 100644 allianceauth/framework/staticfiles/storage.py diff --git a/allianceauth/framework/staticfiles/storage.py b/allianceauth/framework/staticfiles/storage.py new file mode 100644 index 00000000..489b2a79 --- /dev/null +++ b/allianceauth/framework/staticfiles/storage.py @@ -0,0 +1,87 @@ +""" +Custom static files storage for Alliance Auth. + +This module defines a custom static files storage class for +Alliance Auth, named `AaManifestStaticFilesStorage`. + +Using `ManifestStaticFilesStorage` will give us a hashed name for +our static files, which is useful for cache busting. + +This storage class extends Django's `ManifestStaticFilesStorage` to ignore missing files, +which the original class does not handle, and log them in debug mode. +It is useful for handling cases where static files may not exist, such as when a +CSS file references a background image that is not present in the static files directory. + +With debug mode enabled, it will print a message for each missing file when running `collectstatic`, +which can help identify issues with static file references during development. +""" + +from django.conf import settings +from django.contrib.staticfiles.storage import ManifestStaticFilesStorage + + +class AaManifestStaticFilesStorage(ManifestStaticFilesStorage): + """ + Custom static files storage that ignores missing files. + """ + + def __init__(self, *args, **kwargs): + """ + Initialize the static files storage, ignoring missing files. + + :param args: + :type args: + :param kwargs: + :type kwargs: + """ + + self.missing_files = [] + + super().__init__(*args, **kwargs) + + def hashed_name(self, name, *args, **kwargs): + """ + Generate a hashed name for the given static file, ignoring missing files. + + Ignore missing files, e.g. non-existent background image referenced from css. + Returns the original filename if the referenced file doesn't exist. + + :param name: + :type name: + :param args: + :type args: + :param kwargs: + :type kwargs: + :return: + :rtype: + """ + + try: + return super().hashed_name(name, *args, **kwargs) + except ValueError as e: + if settings.DEBUG: + # In debug mode, we log the missing file message + message = e.args[0].split(" with ")[0] + self.missing_files.append(message) + # print(f'\x1b[0;30;41m{message}\x1b[0m') + + return name + + def post_process(self, *args, **kwargs): + """ + Post-process the static files, printing any missing files in debug mode. + + :param args: + :type args: + :param kwargs: + :type kwargs: + :return: + :rtype: + """ + + yield from super().post_process(*args, **kwargs) + + if settings.DEBUG: + # In debug mode, print the missing files + for message in sorted(set(self.missing_files)): + print(f"\x1b[0;30;41m{message}\x1b[0m") diff --git a/allianceauth/project_template/project_name/settings/base.py b/allianceauth/project_template/project_name/settings/base.py index e81cc095..7bbd9c2d 100644 --- a/allianceauth/project_template/project_name/settings/base.py +++ b/allianceauth/project_template/project_name/settings/base.py @@ -219,6 +219,15 @@ USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.10/howto/static-files/ +STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": "allianceauth.framework.staticfiles.storage.AaManifestStaticFilesStorage", + }, +} + STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(PROJECT_DIR, 'static'),