#35493: Allow `./` and `../` in paths when recursively including templates
-------------------------------------------+--------------------------
Reporter: gnpivo | Owner: nobody
Type: Bug | Status: new
Component: Template system | Version: 5.0
Severity: Normal | Keywords: template
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 1
UI/UX: 0 |
-------------------------------------------+--------------------------
Hi. Currently, when trying to recursively include a Django template within
itself using the `include` tag with a path that contains `./` or `../`,
Django raises a `TemplateSyntaxError`. However, using a path that does not
contain `./` or `../` does not raise the error. When the error is raised,
the debug toolbar describes it like this:
> = TemplateSyntaxError at /
>
> The relative path ‘“./ul.html”’ was translated to template name
‘app/ul.html’, the same template in which the tag appears.
Here is an example of a template in a Django app called `app` with the
path `app/templates/app/ul.html` that would produce the error given above:
{{{
<ul>
{% for section in sections %}
<li>
<p>{{
section.name }}</p>
{% if section.sections|length != 0 %}
{% include "./ul.html" with sections=section.sections %}
{% endif %}
</li>
{% endfor %}
</ul>
}}}
However, replacing the directory `./ul.html` with the equivalent
`app/ul.html` makes the error go away (assuming that the project's
`settings.py` specifies `APP_DIRS = True` and the views and URLs are
configured correctly). The actual paths are translated identically in both
cases, and the behavior of the `include` tag should not depend simply on
whether or not the path string uses `./` or `../` (or if it should, this
is not documented in the Django documentation). Therefore, it seems that
this is a bug. The expected behavior is that an error is only raised when
recursively using the `extends` template, not when recursively using the
`include` template.
Contrapositively, it appears that recursively extending a template using
the `extends` tag with a path that does ''not'' contain `./` or `../`
raises a `TemplateDoesNotExist` exception, which is semantically
inaccurate since the template is referencing itself and therefore
necessarily exists.
One possible fix is to modify the `django/template/loader_tags.py` file
(
https://github.com/django/django/blob/main/django/template/loader_tags.py)
such that the error is raised when a template attempts to extend itself
(not when a template attempts to include itself, which would otherwise be
valid). The error handling logic in question starts on line 267 of that
file within the `construct_relative_path` function; perhaps it should live
somewhere in the `do_extends` function instead.
Here is a relevant discussion in the Django forums:
https://forum.djangoproject.com/t/template-recursion-why-does-django-not-
allow-and/31689
--
Ticket URL: <
https://code.djangoproject.com/ticket/35493>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.