2014-11-29 07:05:56 +08:00
|
|
|
# Since this package contains a "django" module, this is required on Python 2.
|
|
|
|
from __future__ import absolute_import
|
|
|
|
|
2015-04-25 03:33:03 +08:00
|
|
|
import sys
|
2015-05-09 04:10:36 +08:00
|
|
|
from importlib import import_module
|
|
|
|
from pkgutil import walk_packages
|
2015-01-08 22:03:43 +08:00
|
|
|
|
2015-05-09 04:10:36 +08:00
|
|
|
from django.apps import apps
|
2014-11-29 07:05:56 +08:00
|
|
|
from django.conf import settings
|
2015-04-25 03:33:03 +08:00
|
|
|
from django.template import TemplateDoesNotExist
|
2015-09-05 22:25:43 +08:00
|
|
|
from django.template.context import make_context
|
2015-09-04 04:12:22 +08:00
|
|
|
from django.template.engine import Engine
|
2015-05-09 04:10:36 +08:00
|
|
|
from django.template.library import InvalidTemplateLibrary
|
2015-04-25 03:33:03 +08:00
|
|
|
from django.utils import six
|
2014-11-29 07:05:56 +08:00
|
|
|
|
|
|
|
from .base import BaseEngine
|
|
|
|
|
|
|
|
|
|
|
|
class DjangoTemplates(BaseEngine):
|
|
|
|
|
|
|
|
app_dirname = 'templates'
|
|
|
|
|
|
|
|
def __init__(self, params):
|
|
|
|
params = params.copy()
|
|
|
|
options = params.pop('OPTIONS').copy()
|
2015-11-08 17:06:07 +08:00
|
|
|
options.setdefault('autoescape', True)
|
2015-02-15 22:42:05 +08:00
|
|
|
options.setdefault('debug', settings.DEBUG)
|
2014-11-29 07:05:56 +08:00
|
|
|
options.setdefault('file_charset', settings.FILE_CHARSET)
|
2015-05-09 04:10:36 +08:00
|
|
|
libraries = options.get('libraries', {})
|
|
|
|
options['libraries'] = self.get_templatetag_libraries(libraries)
|
2014-11-29 07:05:56 +08:00
|
|
|
super(DjangoTemplates, self).__init__(params)
|
|
|
|
self.engine = Engine(self.dirs, self.app_dirs, **options)
|
|
|
|
|
|
|
|
def from_string(self, template_code):
|
2015-04-25 03:33:03 +08:00
|
|
|
return Template(self.engine.from_string(template_code), self)
|
2014-11-29 07:05:56 +08:00
|
|
|
|
2015-09-04 04:12:22 +08:00
|
|
|
def get_template(self, template_name):
|
2015-04-25 03:33:03 +08:00
|
|
|
try:
|
2015-09-04 04:12:22 +08:00
|
|
|
return Template(self.engine.get_template(template_name), self)
|
2015-04-25 03:33:03 +08:00
|
|
|
except TemplateDoesNotExist as exc:
|
|
|
|
reraise(exc, self)
|
2014-11-29 07:05:56 +08:00
|
|
|
|
2015-05-09 04:10:36 +08:00
|
|
|
def get_templatetag_libraries(self, custom_libraries):
|
|
|
|
"""
|
|
|
|
Return a collation of template tag libraries from installed
|
|
|
|
applications and the supplied custom_libraries argument.
|
|
|
|
"""
|
|
|
|
libraries = get_installed_libraries()
|
|
|
|
libraries.update(custom_libraries)
|
|
|
|
return libraries
|
|
|
|
|
2014-11-29 07:05:56 +08:00
|
|
|
|
|
|
|
class Template(object):
|
|
|
|
|
2015-04-25 03:33:03 +08:00
|
|
|
def __init__(self, template, backend):
|
2014-11-29 07:05:56 +08:00
|
|
|
self.template = template
|
2015-04-25 03:33:03 +08:00
|
|
|
self.backend = backend
|
2014-11-29 07:05:56 +08:00
|
|
|
|
2014-11-29 05:13:11 +08:00
|
|
|
@property
|
|
|
|
def origin(self):
|
|
|
|
return self.template.origin
|
|
|
|
|
2014-11-29 07:05:56 +08:00
|
|
|
def render(self, context=None, request=None):
|
2015-11-08 17:06:07 +08:00
|
|
|
context = make_context(context, request, autoescape=self.backend.engine.autoescape)
|
2015-04-25 03:33:03 +08:00
|
|
|
try:
|
|
|
|
return self.template.render(context)
|
|
|
|
except TemplateDoesNotExist as exc:
|
|
|
|
reraise(exc, self.backend)
|
|
|
|
|
|
|
|
|
2016-03-09 11:35:39 +08:00
|
|
|
def copy_exception(exc, backend=None):
|
2015-04-25 03:33:03 +08:00
|
|
|
"""
|
2016-03-09 11:35:39 +08:00
|
|
|
Create a new TemplateDoesNotExist. Preserve its declared attributes and
|
|
|
|
template debug data but discard __traceback__, __context__, and __cause__
|
|
|
|
to make this object suitable for keeping around (in a cache, for example).
|
2015-04-25 03:33:03 +08:00
|
|
|
"""
|
2016-03-09 11:35:39 +08:00
|
|
|
backend = backend or exc.backend
|
|
|
|
new = exc.__class__(*exc.args, tried=exc.tried, backend=backend, chain=exc.chain)
|
2015-04-25 03:33:03 +08:00
|
|
|
if hasattr(exc, 'template_debug'):
|
|
|
|
new.template_debug = exc.template_debug
|
2016-03-09 11:35:39 +08:00
|
|
|
return new
|
|
|
|
|
|
|
|
|
|
|
|
def reraise(exc, backend):
|
|
|
|
"""
|
|
|
|
Reraise TemplateDoesNotExist while maintaining template debug information.
|
|
|
|
"""
|
|
|
|
new = copy_exception(exc, backend)
|
2015-04-25 03:33:03 +08:00
|
|
|
six.reraise(exc.__class__, new, sys.exc_info()[2])
|
2015-05-09 04:10:36 +08:00
|
|
|
|
|
|
|
|
|
|
|
def get_installed_libraries():
|
|
|
|
"""
|
|
|
|
Return the built-in template tag libraries and those from installed
|
|
|
|
applications. Libraries are stored in a dictionary where keys are the
|
|
|
|
individual module names, not the full module paths. Example:
|
|
|
|
django.templatetags.i18n is stored as i18n.
|
|
|
|
"""
|
|
|
|
libraries = {}
|
|
|
|
candidates = ['django.templatetags']
|
|
|
|
candidates.extend(
|
|
|
|
'%s.templatetags' % app_config.name
|
|
|
|
for app_config in apps.get_app_configs())
|
|
|
|
|
|
|
|
for candidate in candidates:
|
|
|
|
try:
|
|
|
|
pkg = import_module(candidate)
|
|
|
|
except ImportError:
|
|
|
|
# No templatetags package defined. This is safe to ignore.
|
|
|
|
continue
|
|
|
|
|
|
|
|
if hasattr(pkg, '__path__'):
|
|
|
|
for name in get_package_libraries(pkg):
|
|
|
|
libraries[name[len(candidate) + 1:]] = name
|
|
|
|
|
|
|
|
return libraries
|
|
|
|
|
|
|
|
|
|
|
|
def get_package_libraries(pkg):
|
|
|
|
"""
|
|
|
|
Recursively yield template tag libraries defined in submodules of a
|
|
|
|
package.
|
|
|
|
"""
|
|
|
|
for entry in walk_packages(pkg.__path__, pkg.__name__ + '.'):
|
|
|
|
try:
|
|
|
|
module = import_module(entry[1])
|
|
|
|
except ImportError as e:
|
|
|
|
raise InvalidTemplateLibrary(
|
|
|
|
"Invalid template library specified. ImportError raised when "
|
|
|
|
"trying to load '%s': %s" % (entry[1], e)
|
|
|
|
)
|
|
|
|
|
|
|
|
if hasattr(module, 'register'):
|
|
|
|
yield entry[1]
|