templating.py 4.8 KB

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