Added support for loading templates from modules

This commit is contained in:
Armin Ronacher 2010-07-04 13:42:00 +02:00
parent 15012af700
commit a38dcd5e2b
3 changed files with 72 additions and 30 deletions

View file

@ -14,7 +14,7 @@ from threading import Lock
from datetime import timedelta, datetime
from itertools import chain
from jinja2 import Environment, PackageLoader, FileSystemLoader
from jinja2 import Environment, BaseLoader, FileSystemLoader, TemplateNotFound
from werkzeug import ImmutableDict, create_environ
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, InternalServerError, NotFound
@ -32,13 +32,38 @@ from flask.module import _ModuleSetupState
_logger_lock = Lock()
def _select_autoescape(filename):
"""Returns `True` if autoescaping should be active for the given
template name.
class _DispatchingJinjaLoader(BaseLoader):
"""A loader that looks for templates in the application and all
the module folders.
"""
if filename is None:
return False
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
def __init__(self, app):
self.app = app
def get_source(self, environment, template):
name = template
loader = None
try:
module, name = template.split('/', 1)
loader = self.app.modules[module].jinja_loader
except (ValueError, KeyError):
pass
if loader is None:
loader = self.app.jinja_loader
try:
return loader.get_source(environment, name)
except TemplateNotFound:
# re-raise the exception with the correct fileame here.
# (the one that includes the prefix)
raise TemplateNotFound(template)
def list_templates(self):
result = self.app.jinja_loader.list_templates()
for name, module in self.app.modules.iteritems():
if module.jinja_loader is not None:
for template in module.jinja_loader.list_templates():
result.append('%s/%s' % (name, template))
return result
class Flask(_PackageBoundObject):
@ -176,7 +201,6 @@ class Flask(_PackageBoundObject):
#: Options that are passed directly to the Jinja2 environment.
jinja_options = ImmutableDict(
autoescape=_select_autoescape,
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
@ -245,6 +269,11 @@ class Flask(_PackageBoundObject):
None: [_default_template_ctx_processor]
}
#: all the loaded modules in a dictionary by name.
#:
#: .. versionadded:: 0.5
self.modules = {}
#: The :class:`~werkzeug.routing.Map` for this instance. You can use
#: this to change the routing converters after the class was created
#: but before any routes are connected. Example::
@ -269,8 +298,7 @@ class Flask(_PackageBoundObject):
view_func=self.send_static_file)
#: The Jinja2 environment. It is created from the
#: :attr:`jinja_options` and the loader that is returned
#: by the :meth:`create_jinja_loader` function.
#: :attr:`jinja_options`.
self.jinja_env = self.create_jinja_environment()
self.init_jinja_globals()
@ -315,16 +343,10 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.5
"""
return Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
def create_jinja_loader(self):
"""Creates the Jinja loader. By default just a package loader for
the configured package is returned that looks up templates in the
`templates` folder. To add other loaders it's possible to
override this method.
"""
return FileSystemLoader(os.path.join(self.root_path, 'templates'))
options = dict(self.jinja_options)
if 'autoescape' not in options:
options['autoescape'] = self.select_jinja_autoescape
return Environment(loader=_DispatchingJinjaLoader(self), **options)
def init_jinja_globals(self):
"""Called directly after the environment was created to inject
@ -339,6 +361,16 @@ class Flask(_PackageBoundObject):
)
self.jinja_env.filters['tojson'] = _tojson_filter
def select_jinja_autoescape(self, filename):
"""Returns `True` if autoescaping should be active for the given
template name.
.. versionadded:: 0.5
"""
if filename is None:
return False
return filename.endswith(('.html', '.htm', '.xml', '.xhtml'))
def update_template_context(self, context):
"""Update the template context with some commonly used variables.
This injects request, session and g into the template context.