unfoldadmin / django-unfold

Modern Django admin theme for seamless interface development
https://unfoldadmin.com
MIT License
1.63k stars 161 forks source link

TemplateDoesNotExist for unfold/forms/wysiwyg.html #706

Closed hernansaa closed 3 weeks ago

hernansaa commented 3 weeks ago

What version of Unfold are you using?

For example: 0.37.0

What version of Django are you using?

5.0.6

Did you checked changelog/commit history, if the bug is not already fixed?

Yes

Did you searched other issues, if the bug is not already fixed?

Yes

Describe your issue

When I override form fields to replace TextField for WysiwygWidget I get TemplateDoesNotExist .

I have the feeling that is related to the loaders.py (I am using unfold together with the django admin and followed this insctrucctions: https://unfoldadmin.com/blog/migrating-django-admin-unfold/).

It seems that the templates loader is not looking at the right path (See image below: Templete Loader Postmortem). It actually doesn't even invoke the custom loader (i don't even know if it should, but I mention it anyways.)

Any help is greatly appreciated.

ERROR image If I copy and paste the wysiwyghtml and related helper files in one of those paths I don't get the error but the widget does not show properly.

settings.py templates configuration

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        #'APP_DIRS': True, # <- This will not work with custom template loader
        'OPTIONS': {
            'loaders': [
                'gs_admin.loaders.UnfoldAdminLoader', # <- New template loader
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
            ],
            'context_processors': [
                'home.context_processors.site_context', # To process the base.html
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

loaders.py

from django.core.validators import EMPTY_VALUES
from django.template.loaders.filesystem import Loader as FilesystemLoader
from django.template.utils import get_app_template_dirs
from django.urls import Resolver404, resolve

from .middleware import _thread_data

class UnfoldAdminLoader(FilesystemLoader):
    def _has_unfold_dir(self, template_dir):
        request = getattr(_thread_data, "request", None)

        if not request or request.path in EMPTY_VALUES:
            return False

        try:
            if "admin" in resolve(request.path).namespaces:
                for dir in template_dir.iterdir():
                    if dir.name == "unfold":
                        return True
        except Resolver404:
            pass

        return False

    def get_dirs(self):
        template_dirs = []

        for template_dir in get_app_template_dirs("templates"):
            if not self._has_unfold_dir(template_dir):
                template_dirs.append(template_dir)

        return template_dirs

admin.py

@admin.register(AboutUs, site=new_admin_site)
class AbouUsAdmin(ModelAdmin):
    compressed_fields = True
    inlines = [TeamMemberInline]
    # list_display = ['branch']

    formfield_overrides = {
        models.TextField: {
            "widget": WysiwygWidget,
        },
    }
hernansaa commented 3 weeks ago

Ok, silly me. I forgot to put the "unfold.contrib.forms" in installed apps in settings.py.

"unfold.contrib.forms" added in settings.py

INSTALLED_APPS = [
    "unfold.apps.BasicAppConfig", # <- Custom app config, not overriding default admin
    "unfold.contrib.filters",  # optional, if special filters are needed
    "unfold.contrib.forms",  # optional, if special form elements are needed
    "unfold.contrib.inlines",  # optional, if special inlines are needed
    "unfold.contrib.import_export",  # optional, if django-import-export package is used
    "unfold.contrib.guardian",  # optional, if django-guardian package is used
    "unfold.contrib.simple_history",  # optional, if django-simple-history package is used
    'home',
    'django.contrib.admin',
    'gs_admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]