Skip to main content

Configuring Template Loaders

Template loaders in this project are responsible for locating and reading template files from various sources. You can configure these loaders to look in specific directories, search within installed applications, or cache templates in memory for better performance.

Configuring Default Loaders

The simplest way to set up template loading is using the DIRS and APP_DIRS options in your TEMPLATES setting. This automatically configures the filesystem.Loader and app_directories.Loader.

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
# Other options...
},
},
]

In this configuration:

  • DIRS tells the filesystem.Loader where to look for global templates.
  • APP_DIRS: True enables the app_directories.Loader, which looks for a templates directory in every application listed in INSTALLED_APPS.

Using Explicit Loaders

For more control, you can define the loaders option explicitly. This is required if you want to use the cached.Loader or provide specific arguments to individual loaders.

Filesystem Loader

The filesystem.Loader (from django.template.loaders.filesystem.Loader) loads templates from the file system. You can pass a list of directories directly to it.

'OPTIONS': {
'loaders': [
('django.template.loaders.filesystem.Loader', [
BASE_DIR / 'templates',
BASE_DIR / 'extra_templates',
]),
],
},

App Directories Loader

The app_directories.Loader (from django.template.loaders.app_directories.Loader) automatically finds templates within installed apps. It does not require additional arguments.

'OPTIONS': {
'loaders': [
'django.template.loaders.app_directories.Loader',
],
},

Optimizing Performance with the Cached Loader

The cached.Loader (from django.template.loaders.cached.Loader) wraps other loaders and stores the compiled Template objects in memory. This avoids repeated disk I/O and parsing, which is essential for production environments.

To use it, provide a tuple where the first element is the cached loader class and the second is a list of the loaders it should wrap.

'OPTIONS': {
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]),
],
},

Behavior in Debug Mode

The cached.Loader handles errors differently based on the DEBUG setting. When a template is not found:

  • If DEBUG is True, it caches a copy of the TemplateDoesNotExist exception to preserve debug information (like the list of paths searched) without creating memory leaks.
  • If DEBUG is False, it simply caches the TemplateDoesNotExist class.

Security and Path Validation

The filesystem.Loader uses safe_join to ensure that templates are only loaded from the allowed directories. If a template name attempts to use ../ to escape the configured DIRS, a SuspiciousFileOperation is caught, and the loader moves on to the next source.

# Internal implementation in django/template/loaders/filesystem.py
def get_template_sources(self, template_name):
for template_dir in self.get_dirs():
try:
name = safe_join(template_dir, template_name)
except SuspiciousFileOperation:
# The joined path was located outside of this template_dir
continue

yield Origin(
name=name,
template_name=template_name,
loader=self,
)

Troubleshooting

Configuration Conflicts

You cannot set APP_DIRS: True if you also provide an explicit loaders list. Doing so will raise an ImproperlyConfigured error: "app_dirs must not be set when loaders is defined."

If you need both, include django.template.loaders.app_directories.Loader in your loaders list instead of using the APP_DIRS shortcut.

Refreshing the Cache

The cached.Loader maintains an internal dictionary self.get_template_cache. In development, if you are using the cached loader and templates are not updating, ensure the reset() method is being called (which Django's autoreloader handles automatically).

# To manually clear the cache if needed
from django.template import engines
engine = engines['django'].engine
for loader in engine.template_loaders:
if hasattr(loader, 'reset'):
loader.reset()