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.

jinja2.py 3.4KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import jinja2
  2. from django.conf import settings
  3. from django.template import TemplateDoesNotExist, TemplateSyntaxError
  4. from django.utils.functional import cached_property
  5. from django.utils.module_loading import import_string
  6. from .base import BaseEngine
  7. class Jinja2(BaseEngine):
  8. app_dirname = 'jinja2'
  9. def __init__(self, params):
  10. params = params.copy()
  11. options = params.pop('OPTIONS').copy()
  12. super().__init__(params)
  13. self.context_processors = options.pop('context_processors', [])
  14. environment = options.pop('environment', 'jinja2.Environment')
  15. environment_cls = import_string(environment)
  16. if 'loader' not in options:
  17. options['loader'] = jinja2.FileSystemLoader(self.template_dirs)
  18. options.setdefault('autoescape', True)
  19. options.setdefault('auto_reload', settings.DEBUG)
  20. options.setdefault('undefined',
  21. jinja2.DebugUndefined if settings.DEBUG else jinja2.Undefined)
  22. self.env = environment_cls(**options)
  23. def from_string(self, template_code):
  24. return Template(self.env.from_string(template_code), self)
  25. def get_template(self, template_name):
  26. try:
  27. return Template(self.env.get_template(template_name), self)
  28. except jinja2.TemplateNotFound as exc:
  29. raise TemplateDoesNotExist(exc.name, backend=self) from exc
  30. except jinja2.TemplateSyntaxError as exc:
  31. new = TemplateSyntaxError(exc.args)
  32. new.template_debug = get_exception_info(exc)
  33. raise new from exc
  34. @cached_property
  35. def template_context_processors(self):
  36. return [import_string(path) for path in self.context_processors]
  37. class Template:
  38. def __init__(self, template, backend):
  39. self.template = template
  40. self.backend = backend
  41. self.origin = Origin(
  42. name=template.filename, template_name=template.name,
  43. )
  44. def render(self, context=None, request=None):
  45. from .utils import csrf_input_lazy, csrf_token_lazy
  46. if context is None:
  47. context = {}
  48. if request is not None:
  49. context['request'] = request
  50. context['csrf_input'] = csrf_input_lazy(request)
  51. context['csrf_token'] = csrf_token_lazy(request)
  52. for context_processor in self.backend.template_context_processors:
  53. context.update(context_processor(request))
  54. return self.template.render(context)
  55. class Origin:
  56. """
  57. A container to hold debug information as described in the template API
  58. documentation.
  59. """
  60. def __init__(self, name, template_name):
  61. self.name = name
  62. self.template_name = template_name
  63. def get_exception_info(exception):
  64. """
  65. Format exception information for display on the debug page using the
  66. structure described in the template API documentation.
  67. """
  68. context_lines = 10
  69. lineno = exception.lineno
  70. lines = list(enumerate(exception.source.strip().split("\n"), start=1))
  71. during = lines[lineno - 1][1]
  72. total = len(lines)
  73. top = max(0, lineno - context_lines - 1)
  74. bottom = min(total, lineno + context_lines)
  75. return {
  76. 'name': exception.filename,
  77. 'message': exception.message,
  78. 'source_lines': lines[top:bottom],
  79. 'line': lineno,
  80. 'before': '',
  81. 'during': during,
  82. 'after': '',
  83. 'total': total,
  84. 'top': top,
  85. 'bottom': bottom,
  86. }