浏览代码

Fixed #20995 -- Added support for iterables of template names to {% include %} template tag.

Thanks Adam Johnson for the review.
Keshav Kumar 5 年之前
父节点
当前提交
f37d548ede

+ 7 - 3
django/template/loader_tags.py

@@ -168,12 +168,16 @@ class IncludeNode(Node):
         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'):

+ 8 - 0
docs/ref/templates/builtins.txt

@@ -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!"``:
 
@@ -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``

+ 2 - 0
docs/releases/3.1.txt

@@ -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
 ~~~~~
 

+ 20 - 0
tests/template_tests/syntax_tests/test_include.py

@@ -243,6 +243,26 @@ class IncludeTests(SimpleTestCase):
         output = outer_tmpl.render(ctx)
         self.assertEqual(output, 'This worked!')
 
+    def test_include_template_iterable(self):
+        engine = Engine.get_default()
+        outer_temp = engine.from_string('{% include var %}')
+        tests = [
+            ('admin/fail.html', 'index.html'),
+            ['admin/fail.html', 'index.html'],
+        ]
+        for template_names in tests:
+            with self.subTest(template_names):
+                output = outer_temp.render(Context({'var': template_names}))
+                self.assertEqual(output, 'index\n')
+
+    def test_include_template_none(self):
+        engine = Engine.get_default()
+        outer_temp = engine.from_string('{% include var %}')
+        ctx = Context({'var': None})
+        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')})