Fixed #27175 -- Deprecated silencing exceptions from the {% include %} template tag.

Thanks Tim Graham for the review.
This commit is contained in:
Jon Dufresne 2016-09-08 18:24:22 -07:00 committed by GitHub
parent 7ca3b391b6
commit 331ca5391e
6 changed files with 53 additions and 10 deletions

View File

@ -1,8 +1,10 @@
import logging import logging
import posixpath import posixpath
import warnings
from collections import defaultdict from collections import defaultdict
from django.utils import six from django.utils import six
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from .base import ( from .base import (
@ -208,10 +210,17 @@ class IncludeNode(Node):
return template.render(context.new(values)) return template.render(context.new(values))
with context.push(**values): with context.push(**values):
return template.render(context) return template.render(context)
except Exception: except Exception as e:
if context.template.engine.debug: if context.template.engine.debug:
raise raise
template_name = getattr(context, 'template_name', None) or 'unknown' template_name = getattr(context, 'template_name', None) or 'unknown'
warnings.warn(
"Rendering {%% include '%s' %%} raised %s. In Django 2.1, "
"this exception will be raised rather than silenced and "
"rendered as an empty string." %
(template_name, e.__class__.__name__),
RemovedInDjango21Warning,
)
logger.warning( logger.warning(
"Exception raised while rendering {%% include %%} for " "Exception raised while rendering {%% include %%} for "
"template '%s'. Empty string rendered instead.", "template '%s'. Empty string rendered instead.",

View File

@ -33,6 +33,9 @@ details on these changes.
* The ``host`` parameter of ``django.utils.http.is_safe_url()`` will be * The ``host`` parameter of ``django.utils.http.is_safe_url()`` will be
removed. removed.
* Silencing of exceptions raised while rendering the ``{% include %}`` template
tag will be removed.
.. _deprecation-removed-in-2.0: .. _deprecation-removed-in-2.0:
2.0 2.0

View File

@ -731,6 +731,11 @@ is turned off, ``{% include %}`` logs a warning to the ``django.template``
logger with the exception that happens while rendering the included template logger with the exception that happens while rendering the included template
and returns an empty string. and returns an empty string.
.. deprecated:: 1.11
Silencing exceptions raised while rendering the ``{% include %}`` template
tag is deprecated. In Django 2.1, the exception will be raised.
.. note:: .. note::
The :ttag:`include` tag should be considered as an implementation of The :ttag:`include` tag should be considered as an implementation of
"render this subtemplate and include the HTML", not as "parse this "render this subtemplate and include the HTML", not as "parse this

View File

@ -528,3 +528,8 @@ Miscellaneous
* The ``host`` parameter of ``django.utils.http.is_safe_url()`` is deprecated * The ``host`` parameter of ``django.utils.http.is_safe_url()`` is deprecated
in favor of the new ``allowed_hosts`` parameter. in favor of the new ``allowed_hosts`` parameter.
* Silencing exceptions raised while rendering the
:ttag:`{% include %} <include>` template tag is deprecated as the behavior is
often more confusing than helpful. In Django 2.1, the exception will be
raised.

View File

@ -1,7 +1,10 @@
import warnings
from django.template import ( from django.template import (
Context, Engine, TemplateDoesNotExist, TemplateSyntaxError, Context, Engine, TemplateDoesNotExist, TemplateSyntaxError,
) )
from django.test import SimpleTestCase from django.test import SimpleTestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango21Warning
from ..utils import setup from ..utils import setup
from .test_basic import basic_templates from .test_basic import basic_templates
@ -41,9 +44,20 @@ class IncludeTagTests(SimpleTestCase):
with self.assertRaises(TemplateDoesNotExist): with self.assertRaises(TemplateDoesNotExist):
template.render(Context({})) template.render(Context({}))
else: else:
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
output = template.render(Context({})) output = template.render(Context({}))
self.assertEqual(output, "ab") self.assertEqual(output, "ab")
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
"Rendering {% include 'include04' %} raised "
"TemplateDoesNotExist. In Django 2.1, this exception will be "
"raised rather than silenced and rendered as an empty string.",
)
@setup({ @setup({
'include 05': 'template with a space', 'include 05': 'template with a space',
'include06': '{% include "include 05"%}', 'include06': '{% include "include 05"%}',
@ -169,6 +183,7 @@ class IncludeTagTests(SimpleTestCase):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
template.render(Context()) template.render(Context())
else: else:
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(Context()), '') self.assertEqual(template.render(Context()), '')
@setup({'include-error08': '{% include "include-fail2" %}'}, include_fail_templates) @setup({'include-error08': '{% include "include-fail2" %}'}, include_fail_templates)
@ -179,6 +194,7 @@ class IncludeTagTests(SimpleTestCase):
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):
template.render(Context()) template.render(Context())
else: else:
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(Context()), '') self.assertEqual(template.render(Context()), '')
@setup({'include-error09': '{% include failed_include %}'}, include_fail_templates) @setup({'include-error09': '{% include failed_include %}'}, include_fail_templates)
@ -190,6 +206,7 @@ class IncludeTagTests(SimpleTestCase):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
template.render(context) template.render(context)
else: else:
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(context), '') self.assertEqual(template.render(context), '')
@setup({'include-error10': '{% include failed_include %}'}, include_fail_templates) @setup({'include-error10': '{% include failed_include %}'}, include_fail_templates)
@ -201,6 +218,7 @@ class IncludeTagTests(SimpleTestCase):
with self.assertRaises(TemplateSyntaxError): with self.assertRaises(TemplateSyntaxError):
template.render(context) template.render(context)
else: else:
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(context), '') self.assertEqual(template.render(context), '')

View File

@ -3,7 +3,8 @@ from __future__ import unicode_literals
import logging import logging
from django.template import Context, Engine, Variable, VariableDoesNotExist from django.template import Context, Engine, Variable, VariableDoesNotExist
from django.test import SimpleTestCase from django.test import SimpleTestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango21Warning
class TestHandler(logging.Handler): class TestHandler(logging.Handler):
@ -104,6 +105,7 @@ class IncludeNodeLoggingTests(BaseTemplateLoggingTestCase):
def test_logs_exceptions_during_rendering_with_debug_disabled(self): def test_logs_exceptions_during_rendering_with_debug_disabled(self):
template = self.engine.from_string('{% include "child" %}') template = self.engine.from_string('{% include "child" %}')
template.name = 'template_name' template.name = 'template_name'
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(self.ctx), '') self.assertEqual(template.render(self.ctx), '')
self.assertEqual( self.assertEqual(
self.test_handler.log_record.getMessage(), self.test_handler.log_record.getMessage(),
@ -115,6 +117,7 @@ class IncludeNodeLoggingTests(BaseTemplateLoggingTestCase):
def test_logs_exceptions_during_rendering_with_no_template_name(self): def test_logs_exceptions_during_rendering_with_no_template_name(self):
template = self.engine.from_string('{% include "child" %}') template = self.engine.from_string('{% include "child" %}')
with ignore_warnings(category=RemovedInDjango21Warning):
self.assertEqual(template.render(self.ctx), '') self.assertEqual(template.render(self.ctx), '')
self.assertEqual( self.assertEqual(
self.test_handler.log_record.getMessage(), self.test_handler.log_record.getMessage(),