templating.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # -*- coding: utf-8 -*-
  2. """
  3. flask.templating
  4. ~~~~~~~~~~~~~~~~
  5. Implements the bridge to Jinja2.
  6. :copyright: (c) 2011 by Armin Ronacher.
  7. :license: BSD, see LICENSE for more details.
  8. """
  9. import posixpath
  10. from jinja2 import BaseLoader, Environment as BaseEnvironment, \
  11. TemplateNotFound
  12. from .globals import _request_ctx_stack, _app_ctx_stack
  13. from .signals import template_rendered
  14. from .module import blueprint_is_module
  15. from ._compat import itervalues, iteritems
  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. for loader, local_name in self._iter_loaders(template):
  47. try:
  48. return loader.get_source(environment, local_name)
  49. except TemplateNotFound:
  50. pass
  51. raise TemplateNotFound(template)
  52. def _iter_loaders(self, template):
  53. loader = self.app.jinja_loader
  54. if loader is not None:
  55. yield loader, template
  56. # old style module based loaders in case we are dealing with a
  57. # blueprint that is an old style module
  58. try:
  59. module, local_name = posixpath.normpath(template).split('/', 1)
  60. blueprint = self.app.blueprints[module]
  61. if blueprint_is_module(blueprint):
  62. loader = blueprint.jinja_loader
  63. if loader is not None:
  64. yield loader, local_name
  65. except (ValueError, KeyError):
  66. pass
  67. for blueprint in itervalues(self.app.blueprints):
  68. if blueprint_is_module(blueprint):
  69. continue
  70. loader = blueprint.jinja_loader
  71. if loader is not None:
  72. yield loader, template
  73. def list_templates(self):
  74. result = set()
  75. loader = self.app.jinja_loader
  76. if loader is not None:
  77. result.update(loader.list_templates())
  78. for name, blueprint in iteritems(self.app.blueprints):
  79. loader = blueprint.jinja_loader
  80. if loader is not None:
  81. for template in loader.list_templates():
  82. prefix = ''
  83. if blueprint_is_module(blueprint):
  84. prefix = name + '/'
  85. result.add(prefix + template)
  86. return list(result)
  87. def _render(template, context, app):
  88. """Renders the template and fires the signal"""
  89. rv = template.render(context)
  90. template_rendered.send(app, template=template, context=context)
  91. return rv
  92. def render_template(template_name_or_list, **context):
  93. """Renders a template from the template folder with the given
  94. context.
  95. :param template_name_or_list: the name of the template to be
  96. rendered, or an iterable with template names
  97. the first one existing will be rendered
  98. :param context: the variables that should be available in the
  99. context of the template.
  100. """
  101. ctx = _app_ctx_stack.top
  102. ctx.app.update_template_context(context)
  103. return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
  104. context, ctx.app)
  105. def render_template_string(source, **context):
  106. """Renders a template from the given template source string
  107. with the given context.
  108. :param source: the sourcecode of the template to be
  109. rendered
  110. :param context: the variables that should be available in the
  111. context of the template.
  112. """
  113. ctx = _app_ctx_stack.top
  114. ctx.app.update_template_context(context)
  115. return _render(ctx.app.jinja_env.from_string(source),
  116. context, ctx.app)