summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2014-11-28 22:13:11 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2014-12-28 16:23:01 +0100
commit4ea43ac915e187fb0c283094504f488d5017d7ec (patch)
tree9c8de42405e8ff74a5ae80ec1ec39fe5102a76a5
parent6854998c8f405248c304cf14ecc46617e8a9f206 (diff)
Supported multiple template engines in get_template and select_template.
This commit changes the return type of these two functions. Instead of returning a django.template.Template they return a backend-specific Template class that must implement render(self, context).
-rw-r--r--django/template/backends/django.py22
-rw-r--r--django/template/base.py2
-rw-r--r--django/template/loader.py68
-rw-r--r--tests/template_tests/tests.py6
4 files changed, 82 insertions, 16 deletions
diff --git a/django/template/backends/django.py b/django/template/backends/django.py
index a8dc2de300..580d789a67 100644
--- a/django/template/backends/django.py
+++ b/django/template/backends/django.py
@@ -3,7 +3,7 @@ from __future__ import absolute_import
from django.conf import settings
from django.template.context import Context, RequestContext
-from django.template.engine import Engine
+from django.template.engine import _dirs_undefined, Engine
from .base import BaseEngine
@@ -24,8 +24,8 @@ class DjangoTemplates(BaseEngine):
def from_string(self, template_code):
return Template(self.engine.from_string(template_code))
- def get_template(self, template_name):
- return Template(self.engine.get_template(template_name))
+ def get_template(self, template_name, dirs=_dirs_undefined):
+ return Template(self.engine.get_template(template_name, dirs))
class Template(object):
@@ -33,9 +33,17 @@ class Template(object):
def __init__(self, template):
self.template = template
+ @property
+ def origin(self):
+ # TODO: define the Origin API. For now simply forwarding to the
+ # underlying Template preserves backwards-compatibility.
+ return self.template.origin
+
def render(self, context=None, request=None):
- if request is None:
- context = Context(context)
- else:
- context = RequestContext(request, context)
+ # TODO: require context to be a dict -- through a deprecation path?
+ if not isinstance(context, Context):
+ if request is None:
+ context = Context(context)
+ else:
+ context = RequestContext(request, context)
return self.template.render(context)
diff --git a/django/template/base.py b/django/template/base.py
index 42c0047079..3d538cb69e 100644
--- a/django/template/base.py
+++ b/django/template/base.py
@@ -1266,6 +1266,8 @@ class Library(object):
if not getattr(self, 'nodelist', False):
if isinstance(file_name, Template):
t = file_name
+ elif isinstance(getattr(file_name, 'template', None), Template):
+ t = file_name.template
elif not isinstance(file_name, six.string_types) and is_iterable(file_name):
t = context.engine.select_template(file_name)
else:
diff --git a/django/template/loader.py b/django/template/loader.py
index d7c42627d1..b76fbdcfb9 100644
--- a/django/template/loader.py
+++ b/django/template/loader.py
@@ -2,8 +2,10 @@ import warnings
from django.utils.deprecation import RemovedInDjango20Warning
-from .base import Origin
-from .engine import Engine
+from . import engines
+from .backends.django import DjangoTemplates
+from .base import Origin, TemplateDoesNotExist
+from .engine import _dirs_undefined, Engine
class LoaderOrigin(Origin):
@@ -19,8 +21,62 @@ def find_template(*args, **kwargs):
return Engine.get_default().find_template(*args, **kwargs)
-def get_template(*args, **kwargs):
- return Engine.get_default().get_template(*args, **kwargs)
+def get_template(template_name, dirs=_dirs_undefined, using=None):
+ """
+ Loads and returns a template for the given name.
+
+ Raises TemplateDoesNotExist if no such template exists.
+ """
+ engines = _engine_list(using)
+ for engine in engines:
+ try:
+ # This is required for deprecating the dirs argument. Simply
+ # return engine.get_template(template_name) in Django 2.0.
+ if isinstance(engine, DjangoTemplates):
+ return engine.get_template(template_name, dirs)
+ elif dirs is not _dirs_undefined:
+ warnings.warn(
+ "Skipping template backend %s because its get_template "
+ "method doesn't support the dirs argument." % engine.name,
+ stacklevel=2)
+ else:
+ return engine.get_template(template_name)
+ except TemplateDoesNotExist:
+ pass
+
+ raise TemplateDoesNotExist(template_name)
+
+
+def select_template(template_name_list, dirs=_dirs_undefined, using=None):
+ """
+ Loads and returns a template for one of the given names.
+
+ Tries names in order and returns the first template found.
+
+ Raises TemplateDoesNotExist if no such template exists.
+ """
+ engines = _engine_list(using)
+ for template_name in template_name_list:
+ for engine in engines:
+ try:
+ # This is required for deprecating the dirs argument. Simply
+ # use engine.get_template(template_name) in Django 2.0.
+ if isinstance(engine, DjangoTemplates):
+ return engine.get_template(template_name, dirs)
+ elif dirs is not _dirs_undefined:
+ warnings.warn(
+ "Skipping template backend %s because its get_template "
+ "method doesn't support the dirs argument." % engine.name,
+ stacklevel=2)
+ else:
+ return engine.get_template(template_name)
+ except TemplateDoesNotExist:
+ pass
+
+ if template_name_list:
+ raise TemplateDoesNotExist(', '.join(template_name_list))
+ else:
+ raise TemplateDoesNotExist("No template names provided")
def get_template_from_string(*args, **kwargs):
@@ -31,8 +87,8 @@ def render_to_string(*args, **kwargs):
return Engine.get_default().render_to_string(*args, **kwargs)
-def select_template(*args, **kwargs):
- return Engine.get_default().select_template(*args, **kwargs)
+def _engine_list(using=None):
+ return engines.all() if using is None else [engines[using]]
# This line must remain at the bottom to avoid import loops.
diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py
index 80f926ea6f..5d4b029430 100644
--- a/tests/template_tests/tests.py
+++ b/tests/template_tests/tests.py
@@ -85,7 +85,7 @@ class TemplateLoaderTests(SimpleTestCase):
# We also rely on the fact the file system and app directories loaders
# both inherit the load_template method from the base Loader class, so
# we only need to test one of them.
- template = loader.get_template(load_name)
+ template = loader.get_template(load_name).template
template_name = template.nodelist[0].source[0].name
self.assertTrue(template_name.endswith(load_name),
'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
@@ -100,12 +100,12 @@ class TemplateLoaderTests(SimpleTestCase):
load_name = 'login.html'
# Test the cached loader separately since it overrides load_template.
- template = loader.get_template(load_name)
+ template = loader.get_template(load_name).template
template_name = template.nodelist[0].source[0].name
self.assertTrue(template_name.endswith(load_name),
'Template loaded through cached loader has incorrect name for debug page: %s' % template_name)
- template = loader.get_template(load_name)
+ template = loader.get_template(load_name).template
template_name = template.nodelist[0].source[0].name
self.assertTrue(template_name.endswith(load_name),
'Cached template loaded through cached loader has incorrect name for debug page: %s' % template_name)