Why is my templates folder being ignored?

I’m trying to create a SplitDateTimeWidget by inheriting from the AdminSplitDateTimeWidget which going fine except it won’t find my template. Since the widget is not tied with an app but rather an infrastructure that many apps will use, I put the widget code in to the project subfolder where the settings.py lives. I have a templates folder in there that I use for custom admin templates amongst others. This template folder also has the basic base.html and body.html that make up the layout of the page. I added this folder in my settings like this:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'bt' / 'templates',
                 BASE_DIR / 'bt' / 'templates' / 'widgets'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

The base.html and body.html are being found. But the SplitTimeWidget.html that I put into the widgets subfolder is not being found. In the error message that I get, neither folder shows up.


Template-loader postmortem

Django tried loading these templates, in this order:
Using engine django:

    django.template.loaders.filesystem.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\venv_win\lib\site-packages\django\forms\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\venv_win\lib\site-packages\django\contrib\admin\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\venv_win\lib\site-packages\django\contrib\auth\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\venv_win\lib\site-packages\bootstrap5\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\user_profiles\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\jobs\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\contacts\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\addresses\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\organisations\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\tasks\templates\split_datetime.html (Source does not exist)
    django.template.loaders.app_directories.Loader: C:\Users\xxx\Documents\Python\Projekte\bt\bt\expenses\templates\split_datetime.html (Source does not exist)

Any suggestions why it is like that?

What does your SplitDateTimeWidget class look like? (What is your setting for the template_name attribute?) If you’re not overriding that attribute, then it’s going to inherit the attribute from the base class.

Also see Overriding built-in widget templates. You should be using the TemplatesSetting renderer.

This is what my class looks like:

class SplitDateTime(forms.SplitDateTimeWidget):
    """
    A SplitDateTime Widget.
    """

    template_name = "split_datetime.html"

    def __init__(self, attrs=None):
        widgets = [AdminDateWidget, AdminTimeWidget]
        # Note that we're calling MultiWidget, not SplitDateTimeWidget, because
        # we want to define widgets.
        forms.MultiWidget.__init__(self, widgets, attrs)

    def get_context(self, name, value, attrs):
        context = super().get_context(name, value, attrs)
        return context

If I put “split_datetime.html” into one of my custom apps and change the template_name accordingly, it works fine, for instance “addresses/split_datetime.html”. It just doesn’t work with the custom template folder.

You should be using the TemplatesSetting renderer.

What exactly do you mean by that? I read what you linked but it’s one of those instances where the Django manual just confuses me.

First, quoting directly from the docs:

To override widget templates, you must use the TemplatesSetting renderer. Then overriding widget templates works the same as overriding any other template in your project.

Hopefully, the first sentence is clear enough. (You may not know how to do this yet, but that’s ok.)

The second sentence here implies that if you don’t do this, then overriding widget templates does not work the same as overriding any other template. This means that it does not use the same search method for finding those templates - which is why you aren’t seeing it.

So, moving on to the linked text in the quoted section:

This renderer gives you complete control of how form and widget templates are sourced. It uses get_template() to find templates based on what’s configured in the TEMPLATES setting.
Using this renderer along with the built-in templates requires either:

So again - making the distinction here between what this does and what the default does, along with giving you two things you need to do when using this.

Now, how to use this? Scrolling up shows that this section of the docs is part of the The form rendering API | Django documentation | Django section. The very first item is DjangoTemplates - and that’s the last piece of this puzzle.

Replace this:

with django.template.backends.django.TemplatesSetting (along with making the other changes referenced above).

1 Like

Thank you Ken for clearing things up. I read over the manual passages a couple of times and still wasn’t sure whether there are several template rendering engines. Now I know for sure. Unfortunately, ‘django.template.backends.django.TemplatesSetting’ does not work.

ImportError: Module “django.template.backends.django” does not define a “TemplatesSetting” attribute/class

I’m using Django 4.1. I found TemplatesSetting in django.forms.renderers.TemplatesSetting. When I used that path I end up with:

TypeError: TemplatesSetting() takes no arguments

I found another thread on that, but it’s unanswered.

Sorry, got myself confused there.

It’s the FORM_RENDERER setting that needs to be made for this, not the general Templates setting.

1 Like

That did it. Thank you.