Hi. When trying to recursively include a Django template using relative paths that contain ./
or ../
, Django raises a TemplateSyntaxError
, which can be traced to line 268 of django/template/loader_tags.py
. However, when using an “absolute” path instead (i.e. a relative path that does not use ./
or ../
), Django does not throw any such error. Why is this a thing? Is there a reason that Django raises an error when using relative paths containing ./
or ../
but not with other ones?
For the sake of a minimal reproducible example, here are some steps to recreate the issue:
- Start a new Django project with
django-admin startproject project
. - Change into the
project
directory and rundjango-admin startapp app
. - Add or modify the files according to the code snippets given below.
- Run the development server with
python manage.py runserver
. - Visit
http://localhost:8000
and confirm that the page displays a simple table of contents. - In
app/templates/app/ul.html
, replace the pathapp/ul.html
with./ul.html
. - Visit
http://localhost:8000
again and observe that theTemplateSyntaxError
is produced.
app/views.py
:
from django.shortcuts import render
def index(request):
# Hierarchal data, from a database perhaps
context = {
"sections": [
{
"name": "Chapter 1: Mastering the art of foo",
"sections": [
{
"name": "Section 1.1: What can foo do for you?",
"sections": [],
},
{
"name": "Section 1.2: A layman's guide to using a foobar",
"sections": [],
},
],
}
],
}
return render(request, "app/ul.html", context)
app/templates/app/ul.html
(after creating the app/templates/app/
directory):
<ul>
{% for section in sections %}
<li>
<p>{{ section.name }}</p>
{% if section.sections|length != 0 %}
{% include "app/ul.html" with sections=section.sections %}
{% endif %}
</li>
{% endfor %}
</ul>
app/urls.py
(a new file):
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
]
project/urls.py
:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("", include("app.urls")),
]
project/settings.py
(to install the app):
# ...
# Install the app we just created
INSTALLED_APPS = [
"app.apps.AppConfig",
# ...
]
# ...
EDIT: I’ve modified the post title and text to clarify what I meant by “absolute” paths in the context of Django templates. The distinction is between paths that use ./
or ../
and paths that do not.