Viewing file: utils.py (3.48 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
import functools from collections import Counter from pathlib import Path
from django.apps import apps from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.utils.functional import cached_property from django.utils.module_loading import import_string
class InvalidTemplateEngineError(ImproperlyConfigured): pass
class EngineHandler: def __init__(self, templates=None): """ templates is an optional list of template engine definitions (structured like settings.TEMPLATES). """ self._templates = templates self._engines = {}
@cached_property def templates(self): if self._templates is None: self._templates = settings.TEMPLATES
templates = {} backend_names = [] for tpl in self._templates: try: # This will raise an exception if 'BACKEND' doesn't exist or # isn't a string containing at least one dot. default_name = tpl['BACKEND'].rsplit('.', 2)[-2] except Exception: invalid_backend = tpl.get('BACKEND', '<not defined>') raise ImproperlyConfigured( "Invalid BACKEND for a template engine: {}. Check " "your TEMPLATES setting.".format(invalid_backend))
tpl = { 'NAME': default_name, 'DIRS': [], 'APP_DIRS': False, 'OPTIONS': {}, **tpl, }
templates[tpl['NAME']] = tpl backend_names.append(tpl['NAME'])
counts = Counter(backend_names) duplicates = [alias for alias, count in counts.most_common() if count > 1] if duplicates: raise ImproperlyConfigured( "Template engine aliases aren't unique, duplicates: {}. " "Set a unique NAME for each engine in settings.TEMPLATES." .format(", ".join(duplicates)))
return templates
def __getitem__(self, alias): try: return self._engines[alias] except KeyError: try: params = self.templates[alias] except KeyError: raise InvalidTemplateEngineError( "Could not find config for '{}' " "in settings.TEMPLATES".format(alias))
# If importing or initializing the backend raises an exception, # self._engines[alias] isn't set and this code may get executed # again, so we must preserve the original params. See #24265. params = params.copy() backend = params.pop('BACKEND') engine_cls = import_string(backend) engine = engine_cls(params)
self._engines[alias] = engine return engine
def __iter__(self): return iter(self.templates)
def all(self): return [self[alias] for alias in self]
@functools.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. """ template_dirs = [ Path(app_config.path) / dirname for app_config in apps.get_app_configs() if app_config.path and (Path(app_config.path) / dirname).is_dir() ] # Immutable return value because it will be cached and shared by callers. return tuple(template_dirs)
|