From 313c3d1aa14d80922003f841c257ec4e153f8653 Mon Sep 17 00:00:00 2001 From: cammil Date: Fri, 7 May 2021 21:49:07 +0100 Subject: [PATCH] Fixed #28935 -- Fixed display of errors in extended blocks. Get the template that caused the exception and get the exception info from that template, using the node that caused the exception. --- django/template/base.py | 13 +++++++++++-- .../templates/test_extends_block_error.html | 2 ++ .../test_extends_block_error_parent.html | 1 + tests/template_tests/tests.py | 17 ++++++++++++++++- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 tests/template_tests/templates/test_extends_block_error.html create mode 100644 tests/template_tests/templates/test_extends_block_error_parent.html diff --git a/django/template/base.py b/django/template/base.py index 4972bd7c58..b47154d88a 100644 --- a/django/template/base.py +++ b/django/template/base.py @@ -926,8 +926,17 @@ class Node: try: return self.render(context) except Exception as e: - if context.template.engine.debug and not hasattr(e, 'template_debug'): - e.template_debug = context.render_context.template.get_exception_info(e, self.token) + if context.template.engine.debug: + # Store the actual node that caused the exception. + if not hasattr(e, '_culprit_node'): + e._culprit_node = self + if ( + not hasattr(e, 'template_debug') and + context.render_context.template.origin == e._culprit_node.origin + ): + e.template_debug = context.render_context.template.get_exception_info( + e, e._culprit_node.token, + ) raise def __iter__(self): diff --git a/tests/template_tests/templates/test_extends_block_error.html b/tests/template_tests/templates/test_extends_block_error.html new file mode 100644 index 0000000000..c4733747a2 --- /dev/null +++ b/tests/template_tests/templates/test_extends_block_error.html @@ -0,0 +1,2 @@ +{% extends "test_extends_block_error_parent.html" %} +{% block content %}{% include "missing.html" %}{% endblock %} diff --git a/tests/template_tests/templates/test_extends_block_error_parent.html b/tests/template_tests/templates/test_extends_block_error_parent.html new file mode 100644 index 0000000000..cb0dbe444b --- /dev/null +++ b/tests/template_tests/templates/test_extends_block_error_parent.html @@ -0,0 +1 @@ +{% block content %}{% endblock %} diff --git a/tests/template_tests/tests.py b/tests/template_tests/tests.py index a8f089c351..5ea026723e 100644 --- a/tests/template_tests/tests.py +++ b/tests/template_tests/tests.py @@ -1,11 +1,14 @@ import sys from django.contrib.auth.models import Group -from django.template import Context, Engine, TemplateSyntaxError +from django.template import ( + Context, Engine, TemplateDoesNotExist, TemplateSyntaxError, +) from django.template.base import UNKNOWN_SOURCE from django.test import SimpleTestCase, override_settings from django.urls import NoReverseMatch from django.utils import translation +from django.utils.html import escape class TemplateTests(SimpleTestCase): @@ -134,6 +137,18 @@ class TemplateTests(SimpleTestCase): t.render(Context()) self.assertEqual(e.exception.template_debug['during'], '{% badtag %}') + def test_render_tag_error_in_extended_block(self): + """Errors in extended block are displayed correctly.""" + e = Engine(app_dirs=True, debug=True) + template = e.get_template('test_extends_block_error.html') + context = Context() + with self.assertRaises(TemplateDoesNotExist) as cm: + template.render(context) + self.assertEqual( + cm.exception.template_debug['during'], + escape('{% include "missing.html" %}'), + ) + def test_super_errors(self): """ #18169 -- NoReverseMatch should not be silence in block.super.