Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actually use the Jinja2 template backend #1882

Merged
merged 2 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions debug_toolbar/panels/templates/jinja2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import functools

from django.template.backends.jinja2 import Template as JinjaTemplate
from django.template.context import make_context
from django.test.signals import template_rendered


def patch_jinja_render():
orig_render = JinjaTemplate.render

@functools.wraps(orig_render)
def wrapped_render(self, context=None, request=None):
# This patching of render only instruments the rendering
# of the immediate template. It won't include the parent template(s).
self.name = self.template.name
template_rendered.send(
sender=self, template=self, context=make_context(context, request)
)
return orig_render(self, context, request)

if JinjaTemplate.render != wrapped_render:
JinjaTemplate.original_render = JinjaTemplate.render
JinjaTemplate.render = wrapped_render
2 changes: 2 additions & 0 deletions debug_toolbar/panels/templates/panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from debug_toolbar.panels import Panel
from debug_toolbar.panels.sql.tracking import SQLQueryTriggered, allow_sql
from debug_toolbar.panels.templates import views
from debug_toolbar.panels.templates.jinja2 import patch_jinja_render

# Monkey-patch to enable the template_rendered signal. The receiver returns
# immediately when the panel is disabled to keep the overhead small.
Expand All @@ -25,6 +26,7 @@
Template.original_render = Template._render
Template._render = instrumented_test_render

patch_jinja_render()

# Monkey-patch to store items added by template context processors. The
# overhead is sufficiently small to justify enabling it unconditionally.
Expand Down
3 changes: 3 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ Pending
-------

* Added check for StreamingHttpResponse in alerts panel.
* Instrument the Django Jinja2 template backend. This only instruments
the immediate template that's rendered. It will not provide stats on
any parent templates.

4.4.3 (2024-07-04)
------------------
Expand Down
8 changes: 7 additions & 1 deletion example/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
STATIC_URL = "/static/"

TEMPLATES = [
{
"NAME": "jinja2",
"BACKEND": "django.template.backends.jinja2.Jinja2",
"APP_DIRS": True,
"DIRS": [os.path.join(BASE_DIR, "example", "templates", "jinja2")],
},
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
Expand All @@ -54,7 +60,7 @@
"django.contrib.messages.context_processors.messages",
],
},
}
},
]

USE_TZ = True
Expand Down
1 change: 1 addition & 0 deletions example/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<h1>Index of Tests</h1>
{% cache 10 index_cache %}
<ul>
<li><a href="{% url 'jinja' %}">Jinja2</a></li>
<li><a href="/jquery/">jQuery 3.3.1</a></li>
<li><a href="/mootools/">MooTools 1.6.0</a></li>
<li><a href="/prototype/">Prototype 1.7.3.0</a></li>
Expand Down
12 changes: 12 additions & 0 deletions example/templates/jinja2/index.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>jinja Test</title>
</head>
<body>
<h1>jinja Test</h1>
{{ foo }}
{% for i in range(10) %}{{ i }}{% endfor %} {# Jinja2 supports range(), Django templates do not #}
</body>
</html>
3 changes: 2 additions & 1 deletion example/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.views.generic import TemplateView

from debug_toolbar.toolbar import debug_toolbar_urls
from example.views import increment
from example.views import increment, jinja2_view

urlpatterns = [
path("", TemplateView.as_view(template_name="index.html"), name="home"),
Expand All @@ -12,6 +12,7 @@
TemplateView.as_view(template_name="bad_form.html"),
name="bad_form",
),
path("jinja/", jinja2_view, name="jinja"),
path("jquery/", TemplateView.as_view(template_name="jquery/index.html")),
path("mootools/", TemplateView.as_view(template_name="mootools/index.html")),
path("prototype/", TemplateView.as_view(template_name="prototype/index.html")),
Expand Down
5 changes: 5 additions & 0 deletions example/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.http import JsonResponse
from django.shortcuts import render


def increment(request):
Expand All @@ -8,3 +9,7 @@ def increment(request):
value = 1
request.session["value"] = value
return JsonResponse({"value": value})


def jinja2_view(request):
return render(request, "index.jinja", {"foo": "bar"}, using="jinja2")
17 changes: 16 additions & 1 deletion tests/panels/test_template.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from unittest import expectedFailure

import django
from django.contrib.auth.models import User
from django.template import Context, RequestContext, Template
Expand Down Expand Up @@ -136,10 +138,23 @@ def test_lazyobject_eval(self):
)
class JinjaTemplateTestCase(IntegrationTestCase):
def test_django_jinja2(self):
r = self.client.get("/regular_jinja/foobar/")
self.assertContains(r, "Test for foobar (Jinja)")
# This should be 2 templates because of the parent template.
# See test_django_jinja2_parent_template_instrumented
self.assertContains(r, "<h3>Templates (1 rendered)</h3>")
self.assertContains(r, "<small>basic.jinja</small>")

@expectedFailure
def test_django_jinja2_parent_template_instrumented(self):
"""
When Jinja2 templates are properly instrumented, the
parent template should be instrumented.
"""
r = self.client.get("/regular_jinja/foobar/")
self.assertContains(r, "Test for foobar (Jinja)")
self.assertContains(r, "<h3>Templates (2 rendered)</h3>")
self.assertContains(r, "<small>jinja2/basic.jinja</small>")
self.assertContains(r, "<small>basic.jinja</small>")


def context_processor(request):
Expand Down
9 changes: 9 additions & 0 deletions tests/templates/jinja2/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
5 changes: 4 additions & 1 deletion tests/templates/jinja2/basic.jinja
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
{% extends 'base.html' %}
{% block content %}Test for {{ title }} (Jinja){% endblock %}
{% block content %}
Test for {{ title }} (Jinja)
{% for i in range(10) %}{{ i }}{% endfor %} {# Jinja2 supports range(), Django templates do not #}
{% endblock %}
2 changes: 1 addition & 1 deletion tests/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def json_view(request):


def regular_jinjia_view(request, title):
return render(request, "jinja2/basic.jinja", {"title": title})
return render(request, "basic.jinja", {"title": title}, using="jinja2")


def listcomp_view(request):
Expand Down
Loading