Reputation: 1186
As described in the documentation, since 4.1 the default behavior for template loading changed drastically.
If I understand it right, until 4.0 it worked like this:
That way, the template caching was seamlessly enabled in production which is great.
Now this ticket proposal was included and, if I get it correctly, the template loading method must be specified and it's not anymore tied to DEBUG setting, AND, by default are cached.
We want the original behavior so the frontend developer can see the changes without having to restart the app, and we also want the production deployment to have the caching enabled, so we did this:
develop_loaders = [
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
]
production_loaders = [
("django.template.loaders.cached.Loader", [
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
"path.to.custom.Loader",
])
]
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [
"templates",
],
"OPTIONS": {
"context_processors": [
"maintenance_mode.context_processors.maintenance_mode",
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"wagtail.contrib.settings.context_processors.settings",
],
"loaders": develop_loaders if DEBUG else production_loaders,
},
},
]
Which works, but I wonder, am I getting the situation correctly? Do you think this is a solid solution?.
Also it took me a while because when I read the changelog for 4.1 I didn't grasp that this change would have this impact (we never specified any loader in settings before) so we expected the default behavior to be respected, which led to looking at gunicorn and docker as the first suspicious culprits, etc... so I thought that this question might be useful for other people in a similar situation.
Upvotes: 10
Views: 1319
Reputation: 752
Yes, you are correct.
Yes, that config will work and is well written.
Here's why.
By default (as of Django 4 / Django 5) the Django TEMPLATES
setting will automatically use a wrapper of django.template.loaders.cached.Loader unless you tell it not to.
This happens by default:
"This loader is automatically enabled if
OPTIONS['loaders']
isn’t specified."https://docs.djangoproject.com/en/5.1/ref/templates/api/#django.template.loaders.cached.Loader
This default cache setting is cumbersome for local development, because to test any template change, you need to either...
Your solution is the best of both worlds: you get caching for production, but you totally ignore caching for local development.
With your settings above, the local shell will always load the latest version of a template file when you run get_template('my_template.html')
.render()
This is not the default behavior today. Without your settings above, subsequent calls to get_template()
will use the first cached version of the file unless you manually invalidate the cache / or restart your shell.
Note: For this answer we will only trace how to configure the settings for the DjangoTemplates
template backend, not Jinja2. Where our use case is: we want to entirely avoid template caching for local development.
Let's begin our journey through the docs at the top level settings page to understand the TEMPLATES
setting:
TEMPLATES = [ .. ]
key"BACKEND"
key has no default, and must be defined for each template dict in TEMPLATES = [ {"BACKEND": .. } ]
.
'django.template.backends.django.DjangoTemplates'
or 'django.template.backends.jinja2.Jinja2'
settings.TEMPLATES[0]["OPTIONS"]
key's values documented either in the DjangoTemplates docs or in the Jinja2 docs, depending on your backend.TEMPLATES[0]["OPTIONS"]
under the section that says "DjangoTemplates
engines accept the following OPTIONS
:"TEMPLATES[0]["OPTIONS"]["loaders"]
under the "loaders"
bullet.
["loaders"]
key while we're still on this page:class cached.Loader
https://docs.djangoproject.com/en/5.1/ref/templates/api/#django.template.loaders.cached.Loader
OPTIONS['loaders']
isn’t specified."
["loaders"]
tuple is the loader to use, and the subsequent items remaining in the tuple become arguments passed to it.TEMPLATES[0]["OPTIONS"]["loaders"]
will use "django.template.loaders.cached.Loader"
as the loader (first item in the tuple) and the list of "django.template.loaders.filesystem.Loader"
and "django.template.loaders.app_directories.Loader"
become arguments passed into it. (This is explicitly stated in the API | Templates | Configuring an engine | class Engine | loaders section at the top of the page, see my next paragraph).Here's an even more explicit section (still in the same page) that says the cached.Loader
is the default:
settings.TEMPLATES
dictionary using TEMPLATES[i]["BACKEND"] == DjangoTemplates
will be wrapped by an Engine instance.TEMPLATES[0]["OPTIONS"]["loaders"]
will be an instance of django.template.loaders.cached.Loader
(that first item in the tuple) and it will wrap
'django.template.loaders.filesystem.Loader'
and'django.template.loaders.app_directories.Loader'
"(if and only if app_dirs is True)"Upvotes: 2
Reputation: 184
The problem is not with the cached loader but with the signal handling of your OS. The cached loader has an reset
method which is called on file_changed
, this way you can benefit even when debugging of the cached templates.
Do you use runserver_plus
? There is an issue for it: https://github.com/django-extensions/django-extensions/issues/1766
I do not experience the issue with normal runserver
command.
Upvotes: 0