Skip to content

Commit

Permalink
Fixed #20995 -- Added support for iterables of template names to {% i…
Browse files Browse the repository at this point in the history
…nclude %} template tag.

Thanks Adam Johnson for the review.
  • Loading branch information
Keshav Kumar authored and felixxm committed Feb 17, 2020
1 parent 8690878 commit 143d87a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 3 deletions.
10 changes: 7 additions & 3 deletions django/template/loader_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,16 @@ def render(self, context):
template = self.template.resolve(context)
# Does this quack like a Template?
if not callable(getattr(template, 'render', None)):
# If not, try the cache and get_template().
template_name = template
# If not, try the cache and select_template().
template_name = template or ()
if isinstance(template_name, str):
template_name = (template_name,)
else:
template_name = tuple(template_name)
cache = context.render_context.dicts[0].setdefault(self, {})
template = cache.get(template_name)
if template is None:
template = context.template.engine.get_template(template_name)
template = context.template.engine.select_template(template_name)
cache[template_name] = template
# Use the base.Template of a backends.django.Template.
elif hasattr(template, 'template'):
Expand Down
8 changes: 8 additions & 0 deletions docs/ref/templates/builtins.txt
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,10 @@ the variable ``template_name``::
The variable may also be any object with a ``render()`` method that accepts a
context. This allows you to reference a compiled ``Template`` in your context.

Additionally, the variable may be an iterable of template names, in which case
the first that can be loaded will be used, as per
:func:`~django.template.loader.select_template`.

An included template is rendered within the context of the template that
includes it. This example produces the output ``"Hello, John!"``:

Expand Down Expand Up @@ -724,6 +728,10 @@ available to the included template::
been evaluated and rendered* - not blocks that can be overridden by, for
example, an extending template.

.. versionchanged:: 3.1

Support for iterables of template names was added.

.. templatetag:: load

``load``
Expand Down
2 changes: 2 additions & 0 deletions docs/releases/3.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ Templates
and :ttag:`blocktrans` template tags aliases continue to work, and will be
retained for the foreseeable future.

* The :ttag:`include` template tag now accepts iterables of template names.

Tests
~~~~~

Expand Down
21 changes: 21 additions & 0 deletions tests/template_tests/syntax_tests/test_include.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,27 @@ def test_include_template_argument(self):
output = outer_tmpl.render(ctx)
self.assertEqual(output, 'This worked!')

def test_include_template_iterable(self):
engine = Engine.get_default()
tests = [
('admin/fail.html', 'index.html'),
['admin/fail.html', 'index.html'],
]
for template_names in tests:
with self.subTest(template_names):
ctx = Context({'var': template_names})
outer_temp = engine.from_string('{% include var %}')
output = outer_temp.render(ctx)
self.assertEqual(output, 'index\n')

def test_include_template_none(self):
engine = Engine.get_default()
ctx = Context({'var': None})
outer_temp = engine.from_string('{% include var %}')
msg = 'No template names provided'
with self.assertRaisesMessage(TemplateDoesNotExist, msg):
outer_temp.render(ctx)

def test_include_from_loader_get_template(self):
tmpl = loader.get_template('include_tpl.html') # {% include tmpl %}
output = tmpl.render({'tmpl': loader.get_template('index.html')})
Expand Down

0 comments on commit 143d87a

Please sign in to comment.