| 1 | > """
|
|---|
| 2 | > Wrapper class that takes a list of template loaders as an argument and attempts
|
|---|
| 3 | > to load templates from them in order, caching the result.
|
|---|
| 4 | > """
|
|---|
| 5 |
|
|---|
| 6 | > import hashlib
|
|---|
| 7 | > from django.template.base import TemplateDoesNotExist
|
|---|
| 8 | > from django.template.loader import BaseLoader, get_template_from_string, find_template_loader, make_origin
|
|---|
| 9 | > from django.utils.encoding import force_bytes
|
|---|
| 10 |
|
|---|
| 11 | > class Loader(BaseLoader):
|
|---|
| 12 | > is_usable = True
|
|---|
| 13 |
|
|---|
| 14 | > def __init__(self, loaders):
|
|---|
| 15 | > self.template_cache = {}
|
|---|
| 16 | > self.find_template_cache = {}
|
|---|
| 17 | > self._loaders = loaders
|
|---|
| 18 | > self._cached_loaders = []
|
|---|
| 19 |
|
|---|
| 20 | > @property
|
|---|
| 21 | > def loaders(self):
|
|---|
| 22 | # Resolve loaders on demand to avoid circular imports
|
|---|
| 23 | > if not self._cached_loaders:
|
|---|
| 24 | # Set self._cached_loaders atomically. Otherwise, another thread
|
|---|
| 25 | # could see an incomplete list. See #17303.
|
|---|
| 26 | ! cached_loaders = []
|
|---|
| 27 | ! for loader in self._loaders:
|
|---|
| 28 | ! cached_loaders.append(find_template_loader(loader))
|
|---|
| 29 | ! self._cached_loaders = cached_loaders
|
|---|
| 30 | > return self._cached_loaders
|
|---|
| 31 |
|
|---|
| 32 | > def cache_key(self, template_name, template_dirs):
|
|---|
| 33 | > if template_dirs:
|
|---|
| 34 | # If template directories were specified, use a hash to differentiate
|
|---|
| 35 | ! return '-'.join([template_name, hashlib.sha1(force_bytes('|'.join(template_dirs))).hexdigest()])
|
|---|
| 36 | > else:
|
|---|
| 37 | > return template_name
|
|---|
| 38 |
|
|---|
| 39 | > def find_template(self, name, dirs=None):
|
|---|
| 40 | > key = self.cache_key(name, dirs)
|
|---|
| 41 | > try:
|
|---|
| 42 | > res = self.find_template_cache[key]
|
|---|
| 43 | > except KeyError:
|
|---|
| 44 | > res = None
|
|---|
| 45 | > for loader in self.loaders:
|
|---|
| 46 | > try:
|
|---|
| 47 | > template, display_name = loader(name, dirs)
|
|---|
| 48 | > res = (template, make_origin(display_name, loader, name, dirs))
|
|---|
| 49 | > except TemplateDoesNotExist:
|
|---|
| 50 | > pass
|
|---|
| 51 | > self.find_template_cache[key] = res
|
|---|
| 52 | > if res:
|
|---|
| 53 | > return res
|
|---|
| 54 | > else:
|
|---|
| 55 | > raise TemplateDoesNotExist(name)
|
|---|
| 56 |
|
|---|
| 57 | > def load_template(self, template_name, template_dirs=None):
|
|---|
| 58 | > key = self.cache_key(template_name, template_dirs)
|
|---|
| 59 | > try:
|
|---|
| 60 | > template = self.template_cache[key]
|
|---|
| 61 | > except KeyError:
|
|---|
| 62 | > template, origin = self.find_template(template_name, template_dirs)
|
|---|
| 63 | > if not hasattr(template, 'render'):
|
|---|
| 64 | > try:
|
|---|
| 65 | > template = get_template_from_string(template, origin, template_name)
|
|---|
| 66 | > except TemplateDoesNotExist:
|
|---|
| 67 | # If compiling the template we found raises TemplateDoesNotExist,
|
|---|
| 68 | # back off to returning the source and display name for the template
|
|---|
| 69 | # we were asked to load. This allows for correct identification (later)
|
|---|
| 70 | # of the actual template that does not exist.
|
|---|
| 71 | > return template, origin
|
|---|
| 72 | > self.template_cache[key] = template
|
|---|
| 73 | > return template, None
|
|---|
| 74 |
|
|---|
| 75 | > def reset(self):
|
|---|
| 76 | > "Empty the template cache."
|
|---|
| 77 | > self.template_cache.clear()
|
|---|
| 78 | > self.find_template_cache.clear()
|
|---|