1 from debug_toolbar.panels import DebugPanel
2 from django.db import connection
3 from django.db.backends import util
4 from django.template.loader import render_to_string
5 from django.shortcuts import render_to_response
6 from django.http import HttpResponse
7 from django.utils import simplejson
10 class DatabaseStatTracker(util.CursorDebugWrapper):
11 """Replacement for CursorDebugWrapper which stores additional information
12 in `connection.queries`."""
13 def execute(self, sql, params=()):
16 return self.cursor.execute(sql, params)
19 # We keep `sql` to maintain backwards compatibility
20 self.db.queries.append({
21 'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
27 util.CursorDebugWrapper = DatabaseStatTracker
29 class SQLDebugPanel(DebugPanel):
31 Panel that displays information about the SQL queries run while processing the request.
35 def reformat_sql(self, sql):
36 sql = sql.replace('`,`', '`, `')
37 sql = sql.replace('` FROM `', '` \n FROM `')
38 sql = sql.replace('` WHERE ', '` \n WHERE ')
39 sql = sql.replace('`) WHERE ', '`) \n WHERE ')
40 sql = sql.replace(' ORDER BY ', ' \n ORDER BY ')
43 def process_ajax(self, request):
44 action = request.GET.get('op')
45 if action == 'explain':
46 # XXX: loop through each sql statement to output explain?
47 sql = request.GET.get('sql', '').split(';')[0]
48 if sql.lower().startswith('select'):
49 if 'params' in request.GET:
50 params = simplejson.loads(request.GET['params'])
53 cursor = connection.cursor()
54 cursor.execute("EXPLAIN %s" % (sql,), params)
55 response = cursor.fetchall()
57 context = {'explain': response, 'sql': self.reformat_sql(sql), 'params': params}
58 return render_to_response('debug_toolbar/panels/sql_explain.html', context)
60 return HttpResponse('Invalid SQL', mimetype="text/plain", status_code=403)
62 def process_request(self, request):
63 self.queries_offset = len(connection.queries)
65 def process_response(self, request, response):
66 self.queries = connection.queries[self.queries_offset:]
67 self.total_time = sum(map(lambda q: float(q['time'])*1000, self.queries))
71 return 'SQL: %.2fms (%d queries)' % (self.total_time, len(self.queries))
77 queries = [(q['time'], q['sql'], q['raw_sql'], simplejson.dumps(q['params'])) for q in sorted(self.queries, key=lambda x: x['time'])[::-1]]
78 context = {'queries': queries}
79 return render_to_string('debug_toolbar/panels/sql.html', context)