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:
DIRStells thefilesystem.Loaderwhere to look for global templates.APP_DIRS: Trueenables theapp_directories.Loader, which looks for atemplatesdirectory in every application listed inINSTALLED_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
DEBUGisTrue, it caches a copy of theTemplateDoesNotExistexception to preserve debug information (like the list of paths searched) without creating memory leaks. - If
DEBUGisFalse, it simply caches theTemplateDoesNotExistclass.
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()