base.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from django.core.exceptions import ImproperlyConfigured, SuspiciousFileOperation
  2. from django.template.utils import get_app_template_dirs
  3. from django.utils._os import safe_join
  4. from django.utils.functional import cached_property
  5. class BaseEngine:
  6. # Core methods: engines have to provide their own implementation
  7. # (except for from_string which is optional).
  8. def __init__(self, params):
  9. """
  10. Initialize the template engine.
  11. `params` is a dict of configuration settings.
  12. """
  13. params = params.copy()
  14. self.name = params.pop("NAME")
  15. self.dirs = list(params.pop("DIRS"))
  16. self.app_dirs = params.pop("APP_DIRS")
  17. if params:
  18. raise ImproperlyConfigured(
  19. "Unknown parameters: {}".format(", ".join(params))
  20. )
  21. def check(self, **kwargs):
  22. return []
  23. @property
  24. def app_dirname(self):
  25. raise ImproperlyConfigured(
  26. "{} doesn't support loading templates from installed "
  27. "applications.".format(self.__class__.__name__)
  28. )
  29. def from_string(self, template_code):
  30. """
  31. Create and return a template for the given source code.
  32. This method is optional.
  33. """
  34. raise NotImplementedError(
  35. "subclasses of BaseEngine should provide a from_string() method"
  36. )
  37. def get_template(self, template_name):
  38. """
  39. Load and return a template for the given name.
  40. Raise TemplateDoesNotExist if no such template exists.
  41. """
  42. raise NotImplementedError(
  43. "subclasses of BaseEngine must provide a get_template() method"
  44. )
  45. # Utility methods: they are provided to minimize code duplication and
  46. # security issues in third-party backends.
  47. @cached_property
  48. def template_dirs(self):
  49. """
  50. Return a list of directories to search for templates.
  51. """
  52. # Immutable return value because it's cached and shared by callers.
  53. template_dirs = tuple(self.dirs)
  54. if self.app_dirs:
  55. template_dirs += get_app_template_dirs(self.app_dirname)
  56. return template_dirs
  57. def iter_template_filenames(self, template_name):
  58. """
  59. Iterate over candidate files for template_name.
  60. Ignore files that don't lie inside configured template dirs to avoid
  61. directory traversal attacks.
  62. """
  63. for template_dir in self.template_dirs:
  64. try:
  65. yield safe_join(template_dir, template_name)
  66. except SuspiciousFileOperation:
  67. # The joined path was located outside of this template_dir
  68. # (it might be inside another one, so this isn't fatal).
  69. pass