#27956 closed Bug (fixed)
Template error raised in an {% extends %} parent template shows incorrect source location on debug page
Reported by: | Ling-Xiao Yang | Owned by: | nobody |
---|---|---|---|
Component: | Template system | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | ling-xiao.yang@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Please see comment:2 for updated description. Below is the original description.
================================================
Hello,
It seems that this problem only concerns Django 1.9 and 1.10. The problem has been fixed in the newest 1.11b1, but I am not sure if it has been backported to older versions.
How to verify:
- Start a new Django project, create two template html files, and make sure that template A uses `{% include %} tag to include the content of template B.
- Make an error inside template B. For example, in the screenshots below, I am passing in a model
Question
and using{{ Question.objects.all }}
in template B (inner.html) to trigger an error. - Complete a view function that renders template A, and add a url route for it. Try access this route with DEBUG=True.
- You will see the debug interface. In the section "Error during template rendering," you will see the error line being highlighted. The position and line number will be correct, but the error will be pointed to template A, while it should be pointed to template B where it actually happens.
Expected behavior:
I attached two screenshots, showing the expected behavior (using Django 1.11b1 and 1.8.11) and the actual behavior (using Django 1.10.6).
Note:
I discovered this problem while investigating the issue 902 of Django debug toolbar (on GitHub).
It is acceptable to invalidate this ticket if the fix has been ported to the branch Django 1.10.x, or it is mentioned elsewhere in the documentation.
Attachments (3)
Change History (12)
by , 8 years ago
Attachment: | 1-8-11.png added |
---|
follow-up: 2 comment:1 by , 8 years ago
Component: | Uncategorized → Template system |
---|---|
Resolution: | → duplicate |
Status: | new → closed |
This is issue #27584. I didn't backport it to 1.9 or 1.10 since the patch wasn't trivial and it went unreported for so long after the release of Django 1.9.
comment:2 by , 8 years ago
Cc: | added |
---|---|
Resolution: | duplicate |
Status: | closed → new |
Version: | 1.10 → master |
Replying to Tim Graham:
This is issue #27584. I didn't backport it to 1.9 or 1.10 since the patch wasn't trivial and it went unreported for so long after the release of Django 1.9.
Hello Tim,
Thank you for pointing to #27584, but it seems that there's still a problem with {% extend %}
tag, although it fixed the {% include %}
tag. In its PR, there's only a unit test for {% include %}
but not for {% extend %}
.
Here's the test for your reference:
27956_child.html
:
{% extends "27956_parent.html" %} {% block content %}{% endblock %}
27956_parent.html
:
{% load tag_27584 %} {% badtag %}{% endbadtag %} {% block content %}{% endblock %}
The unit test:
def test_compile_tag_error_27956(self): engine = Engine( app_dirs=True, debug=True, libraries={'tag_27584': 'template_tests.templatetags.tag_27584'}, ) t = engine.get_template('27956_child.html') with self.assertRaises(TemplateSyntaxError) as e: t.render(Context()) self.assertEqual(e.exception.template_debug['during'], '{% badtag %}')
{% badtag %}
is the one added in #27584's PR that raises a TemplateSyntaxError during its rendering.
And this test doesn't pass on current master branch (7edeeb7):
====================================================================== FAIL: test_compile_tag_error_27956 (template_tests.tests.TemplateTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/python3.5/unittest/case.py", line 58, in testPartExecutor yield File "/usr/lib/python3.5/unittest/case.py", line 600, in run testMethod() File "/home/lxyang/django/tests/template_tests/tests.py", line 134, in test_compile_tag_error_27956 self.assertEqual(e.exception.template_debug['during'], '{% badtag %}') File "/usr/lib/python3.5/unittest/case.py", line 820, in assertEqual assertion_func(first, second, msg=msg) File "/usr/lib/python3.5/unittest/case.py", line 813, in _baseAssertEqual raise self.failureException(msg) AssertionError: 'nt.html" %}\n' != '{% badtag %}' ----------------------------------------------------------------------
If I'm correct at my side, do we consider this still not fixed?
comment:3 by , 8 years ago
Summary: | In DEBUG interface, the section "error during template rendering" doesn't go inside an included template → Template error raised in an {% extends %} parent template shows incorrect source location on debug page |
---|---|
Triage Stage: | Unreviewed → Accepted |
Thanks for clarifying that. I can confirm that's a similar regression as what was fixed in #27584.
comment:4 by , 8 years ago
This is happening because the ExtendsNode calls Template._render
rather than Template.render
:
https://github.com/django/django/blob/master/django/template/loader_tags.py#L152
That means context.render_context.template still references the original template when the debug information is collected:
comment:5 by , 8 years ago
Description: | modified (diff) |
---|
Hello there,
Do we have a reason to have the both _render()
and render()
methods? In django.template, _render()
is not used anywhere else.
Code reference:
~/django$ grep -r "\._render(" . -A 2 -B 2 ./django/forms/widgets.py- """Render the widget as an HTML string.""" ./django/forms/widgets.py- context = self.get_context(name, value, attrs) ./django/forms/widgets.py: return self._render(self.template_name, context, renderer) ./django/forms/widgets.py- ./django/forms/widgets.py- def _render(self, template_name, context, renderer=None): -- ./django/forms/boundfield.py- def tag(self, wrap_label=False): ./django/forms/boundfield.py- context = {'widget': self.data, 'wrap_label': wrap_label} ./django/forms/boundfield.py: return self.parent_widget._render(self.template_name, context, self.renderer) ./django/forms/boundfield.py- ./django/forms/boundfield.py- @property -- ./django/template/loader_tags.py- # Call Template._render explicitly so the parser context stays ./django/template/loader_tags.py- # the same. ./django/template/loader_tags.py: return compiled_parent._render(context) ./django/template/loader_tags.py- ./django/template/loader_tags.py- -- ./django/template/base.py- with context.bind_template(self): ./django/template/base.py- context.template_name = self.name ./django/template/base.py: return self._render(context) ./django/template/base.py- else: ./django/template/base.py: return self._render(context) ./django/template/base.py- ./django/template/base.py- def compile_nodelist(self):
comment:6 by , 8 years ago
I'm pretty sure calling render instead of _render for the extends tag would introduce errors. There's no reason the ExtendsNode can't be updated to set the correct template on context.render_context.template, though.
Django 1.8.11 (correct)