aboutsummaryrefslogtreecommitdiffstats
path: root/debug_toolbar
diff options
context:
space:
mode:
Diffstat (limited to 'debug_toolbar')
-rw-r--r--debug_toolbar/panels/sql.py21
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html4
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql_explain.html25
-rw-r--r--debug_toolbar/urls.py8
-rw-r--r--debug_toolbar/views.py31
5 files changed, 74 insertions, 15 deletions
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
index f23e317..757505a 100644
--- a/debug_toolbar/panels/sql.py
+++ b/debug_toolbar/panels/sql.py
@@ -1,3 +1,4 @@
+import simplejson
import time
from debug_toolbar.panels import DebugPanel
from django.db import connection
@@ -20,7 +21,7 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
'time': stop - start,
'raw_sql': sql,
- 'params': params,
+ 'params': simplejson.dumps(params),
})
util.CursorDebugWrapper = DatabaseStatTracker
@@ -36,13 +37,6 @@ class SQLDebugPanel(DebugPanel):
self._offset = len(connection.queries)
self._sql_time = 0
- def _reformat_sql(self, sql):
- sql = sql.replace('`,`', '`, `')
- sql = sql.replace('` FROM `', '` \n FROM `')
- sql = sql.replace('` WHERE ', '` \n WHERE ')
- sql = sql.replace(' ORDER BY ', ' \n ORDER BY ')
- return sql
-
def title(self):
self._sql_time = sum(map(lambda q: float(q['time']) * 1000, connection.queries))
return '%d SQL Queries (%.2fms)' % (len(connection.queries), self._sql_time)
@@ -53,10 +47,19 @@ class SQLDebugPanel(DebugPanel):
def content(self):
sql_queries = connection.queries[self._offset:]
for query in sql_queries:
- query['sql'] = self._reformat_sql(query['sql'])
+ query['sql'] = reformat_sql(query['sql'])
context = {
'queries': sql_queries,
'sql_time': self._sql_time,
}
return render_to_string('debug_toolbar/panels/sql.html', context)
+
+def reformat_sql(sql):
+ sql = sql.replace('`,`', '`, `')
+ sql = sql.replace('` FROM `', '` \n FROM `')
+ sql = sql.replace('` WHERE ', '` \n WHERE ')
+ sql = sql.replace('` INNER JOIN ', '` \n INNER JOIN ')
+ sql = sql.replace('` OUTER JOIN ', '` \n OUTER JOIN ')
+ sql = sql.replace(' ORDER BY ', ' \n ORDER BY ')
+ return sql
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index 046be7f..246fa74 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -4,13 +4,15 @@
<tr>
<th>Time&nbsp;(ms)</th>
<th>Query</th>
+ <th>Action</th>
</tr>
</thead>
<tbody>
{% for query in queries %}
<tr class="{% cycle 'row1' 'row2' %}">
<td>{{ query.time|floatformat:"4" }}</td>
- <td><pre>{{ query.sql|escape }}</pre></td>
+ <td><pre>{{ query.sql|wordwrap:80|escape }}</pre></td>
+ <td><a href="/__debug__/sql_explain/?sql={{ query.raw_sql|urlencode }}&params={{ query.params|urlencode }}&time={{ query.time|floatformat:"4"|urlencode }}">EXPLAIN</a></td>
</tr>
{% endfor %}
</tbody>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html b/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
new file mode 100644
index 0000000..757d43f
--- /dev/null
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
@@ -0,0 +1,25 @@
+<h3>SQL Explained</h3>
+<dl>
+ <dt>Executed SQL</dt>
+ <dd><pre>{{ sql|wordwrap:80 }}</pre></dd>
+ <dt>Time</dt>
+ <dd>{{ time }} ms</dd>
+</dl>
+<table>
+ <thead>
+ <tr>
+ {% for h in headers %}
+ <th>{{ h|upper }}</th>
+ {% endfor %}
+ </tr>
+ </thead>
+ <tbody>
+ {% for row in result %}
+ <tr class="{% cycle 'row1' 'row2' %}">
+ {% for column in row %}
+ <td>{{ column|escape }}</td>
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </tbody>
+</table>
diff --git a/debug_toolbar/urls.py b/debug_toolbar/urls.py
index 26a5ca2..e0e4b7a 100644
--- a/debug_toolbar/urls.py
+++ b/debug_toolbar/urls.py
@@ -4,10 +4,10 @@ URLpatterns for the debug toolbar.
These should not be loaded explicitly; the debug toolbar middleware will patch
this into the urlconf for the request.
"""
-
from django.conf.urls.defaults import *
from django.conf import settings
-urlpatterns = patterns('',
- url('^__debug__/m/(.*)$', 'debug_toolbar.views.debug_media'),
-) \ No newline at end of file
+urlpatterns = patterns('',
+ url(r'^__debug__/m/(.*)$', 'debug_toolbar.views.debug_media'),
+ url(r'^__debug__/sql_explain/$', 'debug_toolbar.views.sql_explain', name='sql_explain'),
+)
diff --git a/debug_toolbar/views.py b/debug_toolbar/views.py
index 40cc7b1..1b44ed1 100644
--- a/debug_toolbar/views.py
+++ b/debug_toolbar/views.py
@@ -5,12 +5,41 @@ views in any other way is generally not advised.
"""
import os
+import simplejson
import django.views.static
from django.conf import settings
+from django.db import connection
+from django.shortcuts import render_to_response
def debug_media(request, path):
root = getattr(settings, 'DEBUG_TOOLBAR_MEDIA_ROOT', None)
if root is None:
parent = os.path.abspath(os.path.dirname(__file__))
root = os.path.join(parent, 'media')
- return django.views.static.serve(request, path, root) \ No newline at end of file
+ return django.views.static.serve(request, path, root)
+
+def sql_explain(request):
+ """
+ Returns the output of the SQL EXPLAIN on the given query.
+
+ Expected GET variables:
+ sql: urlencoded sql with position arguments
+ params: JSON encoded parameter values
+ time: time for SQL to execute passed in from toolbar just for redisplay
+ """
+ from debug_toolbar.panels.sql import reformat_sql
+ sql = request.GET.get('sql', '')
+ if sql.lower().startswith('select'):
+ params = simplejson.loads(request.GET.get('params', ''))
+ cursor = connection.cursor()
+ cursor.execute("EXPLAIN %s" % (sql,), params)
+ headers = [d[0] for d in cursor.description]
+ result = cursor.fetchall()
+ cursor.close()
+ context = {
+ 'result': result,
+ 'sql': reformat_sql(cursor.db.ops.last_executed_query(cursor, sql, params)),
+ 'time': request.GET.get('time', 0.0),
+ 'headers': headers,
+ }
+ return render_to_response('debug_toolbar/panels/sql_explain.html', context)