Skip to content

Make AJAX views return JSON instead of HTML #1282

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

Merged
merged 1 commit into from
May 19, 2020
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
7 changes: 7 additions & 0 deletions debug_toolbar/panels/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,13 @@ def content(self):
if self.has_content:
return render_to_string(self.template, self.get_stats())

@property
def scripts(self):
"""
Scripts used by the HTML content of the panel when it's displayed.
"""
return []

# URLs for panel-specific views

@classmethod
Expand Down
16 changes: 8 additions & 8 deletions debug_toolbar/panels/sql/views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.http import HttpResponseBadRequest
from django.template.response import SimpleTemplateResponse
from django.http import HttpResponseBadRequest, JsonResponse
from django.template.loader import render_to_string
from django.views.decorators.csrf import csrf_exempt

from debug_toolbar.decorators import require_show_toolbar
Expand Down Expand Up @@ -27,8 +27,8 @@ def sql_select(request):
"headers": headers,
"alias": form.cleaned_data["alias"],
}
# Using SimpleTemplateResponse avoids running global context processors.
return SimpleTemplateResponse("debug_toolbar/panels/sql_select.html", context)
content = render_to_string("debug_toolbar/panels/sql_select.html", context)
return JsonResponse({"content": content})
return HttpResponseBadRequest("Form errors")


Expand Down Expand Up @@ -64,8 +64,8 @@ def sql_explain(request):
"headers": headers,
"alias": form.cleaned_data["alias"],
}
# Using SimpleTemplateResponse avoids running global context processors.
return SimpleTemplateResponse("debug_toolbar/panels/sql_explain.html", context)
content = render_to_string("debug_toolbar/panels/sql_explain.html", context)
return JsonResponse({"content": content})
return HttpResponseBadRequest("Form errors")


Expand Down Expand Up @@ -115,6 +115,6 @@ def sql_profile(request):
"headers": headers,
"alias": form.cleaned_data["alias"],
}
# Using SimpleTemplateResponse avoids running global context processors.
return SimpleTemplateResponse("debug_toolbar/panels/sql_profile.html", context)
content = render_to_string("debug_toolbar/panels/sql_profile.html", context)
return JsonResponse({"content": content})
return HttpResponseBadRequest("Form errors")
8 changes: 4 additions & 4 deletions debug_toolbar/panels/templates/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.core import signing
from django.http import HttpResponseBadRequest
from django.http import HttpResponseBadRequest, JsonResponse
from django.template import Origin, TemplateDoesNotExist
from django.template.engine import Engine
from django.template.response import SimpleTemplateResponse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe

from debug_toolbar.decorators import require_show_toolbar
Expand Down Expand Up @@ -57,8 +57,8 @@ def template_source(request):
except ImportError:
pass

# Using SimpleTemplateResponse avoids running global context processors.
return SimpleTemplateResponse(
content = render_to_string(
"debug_toolbar/panels/template_source.html",
{"source": source, "template_name": template_name},
)
return JsonResponse({"content": content})
7 changes: 7 additions & 0 deletions debug_toolbar/panels/timer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time

from django.template.loader import render_to_string
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _

from debug_toolbar.panels import Panel
Expand Down Expand Up @@ -51,6 +52,12 @@ def content(self):
)
return render_to_string(self.template, {"rows": rows})

@property
def scripts(self):
scripts = super().scripts
scripts.append(static("debug_toolbar/js/toolbar.timer.js"))
return scripts

def process_request(self, request):
self._start_time = time.time()
if self.has_content:
Expand Down
25 changes: 12 additions & 13 deletions debug_toolbar/static/debug_toolbar/js/toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
const style = getComputedStyle(element);
return style.display !== 'none';
},
executeScripts: function(root) {
root.querySelectorAll('script').forEach(function(e) {
const clone = document.createElement('script');
clone.src = e.src;
clone.async = true;
root.appendChild(clone);
executeScripts: function(scripts) {
scripts.forEach(function(script) {
const el = document.createElement('script');
el.src = script;
el.async = true;
document.head.appendChild(el);
});
},
};
Expand All @@ -45,7 +45,7 @@
init = Object.assign({credentials: 'same-origin'}, init);
return fetch(url, init).then(function(response) {
if (response.ok) {
return response.text();
return response.json();
} else {
const win = document.querySelector('#djDebugWindow');
win.innerHTML = '<div class="djDebugPanelTitle"><a class="djDebugClose" href="">»</a><h3>'+response.status+': '+response.statusText+'</h3></div>';
Expand Down Expand Up @@ -82,10 +82,10 @@
url_params.append('store_id', store_id);
url_params.append('panel_id', this.className);
url += '?' + url_params.toString();
ajax(url).then(function(body) {
ajax(url).then(function(data) {
inner.previousElementSibling.remove(); // Remove AJAX loader
inner.innerHTML = body;
$$.executeScripts(inner);
inner.innerHTML = data.content;
$$.executeScripts(data.scripts);
});
}
}
Expand Down Expand Up @@ -121,10 +121,9 @@
ajax_data.url = this.getAttribute('href');
}

ajax(ajax_data.url, ajax_data).then(function(body) {
ajax(ajax_data.url, ajax_data).then(function(data) {
const win = djDebug.querySelector('#djDebugWindow');
win.innerHTML = body;
$$.executeScripts(win);
win.innerHTML = data.content;
$$.show(win);
});
});
Expand Down
3 changes: 1 addition & 2 deletions debug_toolbar/templates/debug_toolbar/panels/timer.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load i18n %}{% load static %}
{% load i18n %}
<h4>{% trans "Resource usage" %}</h4>
<table>
<colgroup>
Expand Down Expand Up @@ -41,4 +41,3 @@ <h4>{% trans "Browser timing" %}</h4>
</tbody>
</table>
</div>
<script src="{% static 'debug_toolbar/js/toolbar.timer.js' %}" aysnc></script>
6 changes: 4 additions & 2 deletions debug_toolbar/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.http import HttpResponse
from django.http import JsonResponse
from django.utils.html import escape
from django.utils.translation import gettext as _

Expand All @@ -16,7 +16,9 @@ def render_panel(request):
"Please reload the page and retry."
)
content = "<p>%s</p>" % escape(content)
scripts = []
else:
panel = toolbar.get_panel_by_id(request.GET["panel_id"])
content = panel.content
return HttpResponse(content)
scripts = panel.scripts
return JsonResponse({"content": content, "scripts": scripts})
11 changes: 11 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@ UNRELEASED
* Updated the italian translation.
* Added support for Django 3.1a1.
* Pruned unused CSS and removed hacks for ancient browsers.
* Added the new :attr:`Panel.scripts <debug_toolbar.panels.Panel.scripts>`
property. This property should return a list of JavaScript resources to be
loaded in the browser when displaying the panel. Right now, this is used by a
single panel, the Timer panel. Third party panels can use this property to
add scripts rather then embedding them in the content HTML.

**Backwards incompatible changes**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Loading panel content no longer executes the scripts elements embedded in the
HTML. Third party panels that require JavaScript resources should now use the
:attr:`Panel.scripts <debug_toolbar.panels.Panel.scripts>` property.

2.2 (2020-01-31)
----------------
Expand Down
2 changes: 2 additions & 0 deletions docs/panels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ unauthorized access. There is no public CSS API at this time.

.. autoattribute:: debug_toolbar.panels.Panel.content

.. autoattribute:: debug_toolbar.panels.Panel.scripts

.. automethod:: debug_toolbar.panels.Panel.get_urls

.. automethod:: debug_toolbar.panels.Panel.enable_instrumentation
Expand Down