diff --git a/django/template/loaders/app_directories.py b/django/template/loaders/app_directories.py index 929c62f217..5e263804f6 100644 --- a/django/template/loaders/app_directories.py +++ b/django/template/loaders/app_directories.py @@ -4,38 +4,16 @@ packages. """ import io -import os -import sys -from django.apps import apps from django.conf import settings from django.core.exceptions import SuspiciousFileOperation from django.template.base import TemplateDoesNotExist +from django.template.utils import get_app_template_dirs from django.utils._os import safe_join -from django.utils import six from .base import Loader as BaseLoader -def calculate_app_template_dirs(): - if six.PY2: - fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() - app_template_dirs = [] - for app_config in apps.get_app_configs(): - if not app_config.path: - continue - template_dir = os.path.join(app_config.path, 'templates') - if os.path.isdir(template_dir): - if six.PY2: - template_dir = template_dir.decode(fs_encoding) - app_template_dirs.append(template_dir) - return tuple(app_template_dirs) - - -# At compile time, cache the directories to search. -app_template_dirs = calculate_app_template_dirs() - - class Loader(BaseLoader): is_usable = True @@ -46,7 +24,7 @@ class Loader(BaseLoader): template dirs are excluded from the result set, for security reasons. """ if not template_dirs: - template_dirs = app_template_dirs + template_dirs = get_app_template_dirs('templates') for template_dir in template_dirs: try: yield safe_join(template_dir, template_name) diff --git a/django/template/utils.py b/django/template/utils.py new file mode 100644 index 0000000000..48e4f9abed --- /dev/null +++ b/django/template/utils.py @@ -0,0 +1,29 @@ +import os +import sys + +from django.apps import apps +from django.utils import lru_cache +from django.utils import six + + +@lru_cache.lru_cache() +def get_app_template_dirs(dirname): + """ + Return an iterable of paths of directories to load app templates from. + + dirname is the name of the subdirectory containing templates inside + installed applications. + """ + if six.PY2: + fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() + template_dirs = [] + for app_config in apps.get_app_configs(): + if not app_config.path: + continue + template_dir = os.path.join(app_config.path, dirname) + if os.path.isdir(template_dir): + if six.PY2: + template_dir = template_dir.decode(fs_encoding) + template_dirs.append(template_dir) + # Immutable return value because it will be cached and shared by callers. + return tuple(template_dirs) diff --git a/django/test/signals.py b/django/test/signals.py index 0f9c5b1fa1..e080d976ee 100644 --- a/django/test/signals.py +++ b/django/test/signals.py @@ -39,9 +39,9 @@ def update_installed_apps(**kwargs): # Rebuild templatetags module cache. from django.template import base as mod mod.templatetags_modules = [] - # Rebuild app_template_dirs cache. - from django.template.loaders import app_directories as mod - mod.app_template_dirs = mod.calculate_app_template_dirs() + # Rebuild get_app_template_dirs cache. + from django.template.utils import get_app_template_dirs + get_app_template_dirs.cache_clear() # Rebuild translations cache. from django.utils.translation import trans_real trans_real._translations = {}