Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

engine.py 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import functools
  2. from django.core.exceptions import ImproperlyConfigured
  3. from django.utils.functional import cached_property
  4. from django.utils.module_loading import import_string
  5. from .base import Context, Template
  6. from .context import _builtin_context_processors
  7. from .exceptions import TemplateDoesNotExist
  8. from .library import import_library
  9. class Engine:
  10. default_builtins = [
  11. 'django.template.defaulttags',
  12. 'django.template.defaultfilters',
  13. 'django.template.loader_tags',
  14. ]
  15. def __init__(self, dirs=None, app_dirs=False, context_processors=None,
  16. debug=False, loaders=None, string_if_invalid='',
  17. file_charset='utf-8', libraries=None, builtins=None, autoescape=True):
  18. if dirs is None:
  19. dirs = []
  20. if context_processors is None:
  21. context_processors = []
  22. if loaders is None:
  23. loaders = ['django.template.loaders.filesystem.Loader']
  24. if app_dirs:
  25. loaders += ['django.template.loaders.app_directories.Loader']
  26. if not debug:
  27. loaders = [('django.template.loaders.cached.Loader', loaders)]
  28. else:
  29. if app_dirs:
  30. raise ImproperlyConfigured(
  31. "app_dirs must not be set when loaders is defined.")
  32. if libraries is None:
  33. libraries = {}
  34. if builtins is None:
  35. builtins = []
  36. self.dirs = dirs
  37. self.app_dirs = app_dirs
  38. self.autoescape = autoescape
  39. self.context_processors = context_processors
  40. self.debug = debug
  41. self.loaders = loaders
  42. self.string_if_invalid = string_if_invalid
  43. self.file_charset = file_charset
  44. self.libraries = libraries
  45. self.template_libraries = self.get_template_libraries(libraries)
  46. self.builtins = self.default_builtins + builtins
  47. self.template_builtins = self.get_template_builtins(self.builtins)
  48. @staticmethod
  49. @functools.lru_cache()
  50. def get_default():
  51. """
  52. Return the first DjangoTemplates backend that's configured, or raise
  53. ImproperlyConfigured if none are configured.
  54. This is required for preserving historical APIs that rely on a
  55. globally available, implicitly configured engine such as:
  56. >>> from django.template import Context, Template
  57. >>> template = Template("Hello {{ name }}!")
  58. >>> context = Context({'name': "world"})
  59. >>> template.render(context)
  60. 'Hello world!'
  61. """
  62. # Since Engine is imported in django.template and since
  63. # DjangoTemplates is a wrapper around this Engine class,
  64. # local imports are required to avoid import loops.
  65. from django.template import engines
  66. from django.template.backends.django import DjangoTemplates
  67. for engine in engines.all():
  68. if isinstance(engine, DjangoTemplates):
  69. return engine.engine
  70. raise ImproperlyConfigured('No DjangoTemplates backend is configured.')
  71. @cached_property
  72. def template_context_processors(self):
  73. context_processors = _builtin_context_processors
  74. context_processors += tuple(self.context_processors)
  75. return tuple(import_string(path) for path in context_processors)
  76. def get_template_builtins(self, builtins):
  77. return [import_library(x) for x in builtins]
  78. def get_template_libraries(self, libraries):
  79. loaded = {}
  80. for name, path in libraries.items():
  81. loaded[name] = import_library(path)
  82. return loaded
  83. @cached_property
  84. def template_loaders(self):
  85. return self.get_template_loaders(self.loaders)
  86. def get_template_loaders(self, template_loaders):
  87. loaders = []
  88. for template_loader in template_loaders:
  89. loader = self.find_template_loader(template_loader)
  90. if loader is not None:
  91. loaders.append(loader)
  92. return loaders
  93. def find_template_loader(self, loader):
  94. if isinstance(loader, (tuple, list)):
  95. args = list(loader[1:])
  96. loader = loader[0]
  97. else:
  98. args = []
  99. if isinstance(loader, str):
  100. loader_class = import_string(loader)
  101. return loader_class(self, *args)
  102. else:
  103. raise ImproperlyConfigured(
  104. "Invalid value in template loaders configuration: %r" % loader)
  105. def find_template(self, name, dirs=None, skip=None):
  106. tried = []
  107. for loader in self.template_loaders:
  108. try:
  109. template = loader.get_template(name, skip=skip)
  110. return template, template.origin
  111. except TemplateDoesNotExist as e:
  112. tried.extend(e.tried)
  113. raise TemplateDoesNotExist(name, tried=tried)
  114. def from_string(self, template_code):
  115. """
  116. Return a compiled Template object for the given template code,
  117. handling template inheritance recursively.
  118. """
  119. return Template(template_code, engine=self)
  120. def get_template(self, template_name):
  121. """
  122. Return a compiled Template object for the given template name,
  123. handling template inheritance recursively.
  124. """
  125. template, origin = self.find_template(template_name)
  126. if not hasattr(template, 'render'):
  127. # template needs to be compiled
  128. template = Template(template, origin, template_name, engine=self)
  129. return template
  130. def render_to_string(self, template_name, context=None):
  131. """
  132. Render the template specified by template_name with the given context.
  133. For use in Django's test suite.
  134. """
  135. if isinstance(template_name, (list, tuple)):
  136. t = self.select_template(template_name)
  137. else:
  138. t = self.get_template(template_name)
  139. # Django < 1.8 accepted a Context in `context` even though that's
  140. # unintended. Preserve this ability but don't rewrap `context`.
  141. if isinstance(context, Context):
  142. return t.render(context)
  143. else:
  144. return t.render(Context(context))
  145. def select_template(self, template_name_list):
  146. """
  147. Given a list of template names, return the first that can be loaded.
  148. """
  149. if not template_name_list:
  150. raise TemplateDoesNotExist("No template names provided")
  151. not_found = []
  152. for template_name in template_name_list:
  153. try:
  154. return self.get_template(template_name)
  155. except TemplateDoesNotExist as exc:
  156. if exc.args[0] not in not_found:
  157. not_found.append(exc.args[0])
  158. continue
  159. # If we get here, none of the templates could be loaded
  160. raise TemplateDoesNotExist(', '.join(not_found))