1from pathlib import Path
2
3from django.dispatch import receiver
4from django.template import engines
5from django.template.backends.django import DjangoTemplates
6from django.utils._os import to_path
7from django.utils.autoreload import autoreload_started, file_changed, is_django_path
8
9
10def get_template_directories():
11 # Iterate through each template backend and find
12 # any template_loader that has a 'get_dirs' method.
13 # Collect the directories, filtering out Django templates.
14 cwd = Path.cwd()
15 items = set()
16 for backend in engines.all():
17 if not isinstance(backend, DjangoTemplates):
18 continue
19
20 items.update(cwd / to_path(dir) for dir in backend.engine.dirs if dir)
21
22 for loader in backend.engine.template_loaders:
23 if not hasattr(loader, "get_dirs"):
24 continue
25 items.update(
26 cwd / to_path(directory)
27 for directory in loader.get_dirs()
28 if directory and not is_django_path(directory)
29 )
30 return items
31
32
33def reset_loaders():
34 from django.forms.renderers import get_default_renderer
35
36 for backend in engines.all():
37 if not isinstance(backend, DjangoTemplates):
38 continue
39 for loader in backend.engine.template_loaders:
40 loader.reset()
41
42 backend = getattr(get_default_renderer(), "engine", None)
43 if isinstance(backend, DjangoTemplates):
44 for loader in backend.engine.template_loaders:
45 loader.reset()
46
47
48@receiver(autoreload_started, dispatch_uid="template_loaders_watch_changes")
49def watch_for_template_changes(sender, **kwargs):
50 for directory in get_template_directories():
51 sender.watch_dir(directory, "**/*")
52
53
54@receiver(file_changed, dispatch_uid="template_loaders_file_changed")
55def template_changed(sender, file_path, **kwargs):
56 if file_path.suffix == ".py":
57 return
58 for template_dir in get_template_directories():
59 if template_dir in file_path.parents:
60 reset_loaders()
61 return True