templating.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. # -*- coding: utf-8 -*-
  2. """
  3. flask.templating
  4. ~~~~~~~~~~~~~~~~
  5. Implements the bridge to Jinja2.
  6. :copyright: 2010 Pallets
  7. :license: BSD-3-Clause
  8. """
  9. from jinja2 import BaseLoader
  10. from jinja2 import Environment as BaseEnvironment
  11. from jinja2 import TemplateNotFound
  12. from .globals import _app_ctx_stack
  13. from .globals import _request_ctx_stack
  14. from .signals import before_render_template
  15. from .signals import template_rendered
  16. def _default_template_ctx_processor():
  17. """Default template context processor. Injects `request`,
  18. `session` and `g`.
  19. """
  20. reqctx = _request_ctx_stack.top
  21. appctx = _app_ctx_stack.top
  22. rv = {}
  23. if appctx is not None:
  24. rv["g"] = appctx.g
  25. if reqctx is not None:
  26. rv["request"] = reqctx.request
  27. rv["session"] = reqctx.session
  28. return rv
  29. class Environment(BaseEnvironment):
  30. """Works like a regular Jinja2 environment but has some additional
  31. knowledge of how Flask's blueprint works so that it can prepend the
  32. name of the blueprint to referenced templates if necessary.
  33. """
  34. def __init__(self, app, **options):
  35. if "loader" not in options:
  36. options["loader"] = app.create_global_jinja_loader()
  37. BaseEnvironment.__init__(self, **options)
  38. self.app = app
  39. class DispatchingJinjaLoader(BaseLoader):
  40. """A loader that looks for templates in the application and all
  41. the blueprint folders.
  42. """
  43. def __init__(self, app):
  44. self.app = app
  45. def get_source(self, environment, template):
  46. if self.app.config["EXPLAIN_TEMPLATE_LOADING"]:
  47. return self._get_source_explained(environment, template)
  48. return self._get_source_fast(environment, template)
  49. def _get_source_explained(self, environment, template):
  50. attempts = []
  51. trv = None
  52. for srcobj, loader in self._iter_loaders(template):
  53. try:
  54. rv = loader.get_source(environment, template)
  55. if trv is None:
  56. trv = rv
  57. except TemplateNotFound:
  58. rv = None
  59. attempts.append((loader, srcobj, rv))
  60. from .debughelpers import explain_template_loading_attempts
  61. explain_template_loading_attempts(self.app, template, attempts)
  62. if trv is not None:
  63. return trv
  64. raise TemplateNotFound(template)
  65. def _get_source_fast(self, environment, template):
  66. for _srcobj, loader in self._iter_loaders(template):
  67. try:
  68. return loader.get_source(environment, template)
  69. except TemplateNotFound:
  70. continue
  71. raise TemplateNotFound(template)
  72. def _iter_loaders(self, template):
  73. loader = self.app.jinja_loader
  74. if loader is not None:
  75. yield self.app, loader
  76. for blueprint in self.app.iter_blueprints():
  77. loader = blueprint.jinja_loader
  78. if loader is not None:
  79. yield blueprint, loader
  80. def list_templates(self):
  81. result = set()
  82. loader = self.app.jinja_loader
  83. if loader is not None:
  84. result.update(loader.list_templates())
  85. for blueprint in self.app.iter_blueprints():
  86. loader = blueprint.jinja_loader
  87. if loader is not None:
  88. for template in loader.list_templates():
  89. result.add(template)
  90. return list(result)
  91. def _render(template, context, app):
  92. """Renders the template and fires the signal"""
  93. before_render_template.send(app, template=template, context=context)
  94. rv = template.render(context)
  95. template_rendered.send(app, template=template, context=context)
  96. return rv
  97. def render_template(template_name_or_list, **context):
  98. """Renders a template from the template folder with the given
  99. context.
  100. :param template_name_or_list: the name of the template to be
  101. rendered, or an iterable with template names
  102. the first one existing will be rendered
  103. :param context: the variables that should be available in the
  104. context of the template.
  105. """
  106. ctx = _app_ctx_stack.top
  107. ctx.app.update_template_context(context)
  108. return _render(
  109. ctx.app.jinja_env.get_or_select_template(template_name_or_list),
  110. context,
  111. ctx.app,
  112. )
  113. def render_template_string(source, **context):
  114. """Renders a template from the given template source string
  115. with the given context. Template variables will be autoescaped.
  116. :param source: the source code of the template to be
  117. rendered
  118. :param context: the variables that should be available in the
  119. context of the template.
  120. """
  121. ctx = _app_ctx_stack.top
  122. ctx.app.update_template_context(context)
  123. return _render(ctx.app.jinja_env.from_string(source), context, ctx.app)