diff options
Diffstat (limited to 'debug_toolbar')
| -rw-r--r-- | debug_toolbar/panels/sql.py | 21 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql.html | 4 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/sql_explain.html | 25 | ||||
| -rw-r--r-- | debug_toolbar/urls.py | 8 | ||||
| -rw-r--r-- | debug_toolbar/views.py | 31 |
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 (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 }}¶ms={{ 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) |
