Source code for render_static.backends.django
"""
Extensions of the standard Django template backends that add a few more
configuration parameters and functionality necessary for the static engine.
These backends should be used instead of the standard backends!
"""
from typing import Dict, Generator, List
from django.template import Template, TemplateDoesNotExist
from django.template.backends.django import DjangoTemplates
from render_static.loaders.django import SearchableLoader
from render_static.loaders.mixins import BatchLoaderMixin
from .base import StaticEngine
__all__ = ["StaticDjangoTemplates"]
[docs]
class StaticDjangoTemplates(StaticEngine, DjangoTemplates):
"""
Extend the standard :class:`django.template.backends.django.DjangoTemplates`
backend to add options and change the default loaders.
By default this backend will search for templates in application
directories named ``static_templates``. The ``app_dir`` option is added to
the standard options to allow users to override this location.
"""
_app_dirname: str = "static_templates"
@property
def app_dirname(self) -> str:
return self._app_dirname
[docs]
def __init__(self, params: Dict) -> None:
"""
:param params: The parameters as passed into the :setting:`STATIC_TEMPLATES`
configuration for this backend.
"""
params = params.copy()
options = params.pop("OPTIONS").copy()
loaders = options.get("loaders", None)
options.setdefault("builtins", ["render_static.templatetags.render_static"])
self._app_dirname = options.pop("app_dir", self.app_dirname)
if loaders is None:
loaders = ["render_static.loaders.StaticFilesystemLoader"]
if params.get("APP_DIRS", False):
loaders += ["render_static.loaders.StaticAppDirectoriesLoader"]
# base class with throw if this isn't present, it must be false
params["APP_DIRS"] = False
options["loaders"] = loaders
params["OPTIONS"] = options
super().__init__(params)
setattr(self.engine, "app_dirname", self.app_dirname)
def select_templates(
self, selector: str, first_loader: bool = False, first_preference: bool = False
) -> List[str]:
"""
Resolves a template selector into a list of template names from the
loaders configured on this backend engine.
:param selector: The template selector
:param first_loader: If True, return only the set of template names
from the first loader that matches any part of the selector. By
default (False) any template name that matches the selector from
any loader will be returned.
:param first_preference: If true, return only the templates that match
the first preference for each loader. When combined with
first_loader will return only the first preference(s) of the first
loader. Preferences are loader specific and documented on the
loader.
:return: The list of resolved template names
"""
template_names = set()
for loader in self.engine.template_loaders:
try:
if isinstance(loader, BatchLoaderMixin):
for templates in loader.select_templates(selector):
for tmpl in templates:
template_names.add(tmpl)
if templates and first_preference:
break
else:
loader.get_template(selector)
template_names.add(selector)
if first_loader and template_names:
return list(template_names)
except TemplateDoesNotExist:
continue
if template_names:
return list(template_names)
raise TemplateDoesNotExist(
f"Template selector {selector} did not resolve to any template names."
)
def search_templates(
self, prefix: str, first_loader: bool = False
) -> Generator[Template, None, None]:
"""
Resolves a partial template selector into a list of template names from the
loaders configured on this backend engine.
:param prefix: The template prefix to search for
:param first_loader: Search only the first loader
:return: The list of resolved template names
"""
for loader in self.engine.template_loaders[: 1 if first_loader else None]:
if isinstance(loader, SearchableLoader):
yield from loader.search(prefix)