Skip to content
15 changes: 9 additions & 6 deletions debug_toolbar/panels/templates/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ def template_source(request):
template_name = request.GET.get("template", template_origin_name)

final_loaders = []
loaders = Engine.get_default().template_loaders
loaders = list(Engine.get_default().template_loaders)

while loaders:
loader = loaders.pop(0)

for loader in loaders:
if loader is not None:
# When the loader has loaders associated with it,
# append those loaders to the list. This occurs with
# django.template.loaders.cached.Loader
# Recursively unwrap loaders until we get to loaders which do not
# themselves wrap other loaders. This adds support for
# django.template.loaders.cached.Loader and the
# django-template-partials loader (possibly among others)
if hasattr(loader, "loaders"):
final_loaders += loader.loaders
loaders.extend(loader.loaders)
else:
final_loaders.append(loader)

Expand Down
3 changes: 3 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Pending
* Added hook to RedirectsPanel for subclass customization.
* Added feature to sanitize sensitive data in the Request Panel.
* Fixed dark mode conflict in code block toolbar CSS
* Added support for using django-template-partials with the template panel's
source view functionality. The same change possibly adds support for other
template loaders.

5.1.0 (2025-03-20)
------------------
Expand Down
18 changes: 18 additions & 0 deletions tests/panels/test_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,24 @@ def test_lazyobject_eval(self):
self.panel.generate_stats(self.request, response)
self.assertIn("lazy_value", self.panel.content)

@override_settings(
DEBUG=True,
DEBUG_TOOLBAR_PANELS=["debug_toolbar.panels.templates.TemplatesPanel"],
)
def test_template_source(self):
from django.core import signing
from django.template.loader import get_template

template = get_template("basic.html")
url = "/__debug__/template_source/"
data = {
"template": template.template.name,
"template_origin": signing.dumps(template.template.origin.name),
}

response = self.client.get(url, data)
self.assertEqual(response.status_code, 200)


@override_settings(
DEBUG=True, DEBUG_TOOLBAR_PANELS=["debug_toolbar.panels.templates.TemplatesPanel"]
Expand Down
5 changes: 5 additions & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

# Quick-start development settings - unsuitable for production

DEBUG = False
SECRET_KEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

INTERNAL_IPS = ["127.0.0.1"]
Expand All @@ -27,6 +28,10 @@
"django.contrib.messages",
"django.contrib.staticfiles",
"debug_toolbar",
# We are not actively using template-partials; we just want more nesting
# in our template loader configuration, see
# https://github.com/django-commons/django-debug-toolbar/issues/2109
"template_partials",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we always be testing with template partials? I think with the django-csp tests, we have specific tests that install the package and test against it. That said, this is likely to be a short-time thing. Both django-csp and template-partials are very likely to be merged to core in the 6.x series.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does feel a bit bad, I agree. Another way to test this would have been to add a mock loader with a loaders attribute containing the cached loader configuration and testing the panel like that. I thought it easier and more understandable to add django-template-partials as a test dependency than doing the more involved mocking.

We will have to revisit this when template-partials is merged (hopefully), either by switching to a different package which also wraps the cached loader or by adding the relevant testing code to our project.

"tests",
]

Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ deps =
selenium>=4.8.0
sqlparse
django-csp
django-template-partials
passenv=
CI
COVERAGE_ARGS
Expand Down