X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/85b57aa2d25552d82260ce40fd9b1063dd7c3dd5..bb68c8efe90a6f818c2c26f36ef0e02c91ed6158:/apps/debug_toolbar/panels/sql.py diff --git a/apps/debug_toolbar/panels/sql.py b/apps/debug_toolbar/panels/sql.py new file mode 100644 index 000000000..977e3155b --- /dev/null +++ b/apps/debug_toolbar/panels/sql.py @@ -0,0 +1,79 @@ +from debug_toolbar.panels import DebugPanel +from django.db import connection +from django.db.backends import util +from django.template.loader import render_to_string +from django.shortcuts import render_to_response +from django.http import HttpResponse +from django.utils import simplejson +from time import time + +class DatabaseStatTracker(util.CursorDebugWrapper): + """Replacement for CursorDebugWrapper which stores additional information + in `connection.queries`.""" + def execute(self, sql, params=()): + start = time() + try: + return self.cursor.execute(sql, params) + finally: + stop = time() + # We keep `sql` to maintain backwards compatibility + self.db.queries.append({ + 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), + 'time': stop - start, + 'raw_sql': sql, + 'params': params, + }) + +util.CursorDebugWrapper = DatabaseStatTracker + +class SQLDebugPanel(DebugPanel): + """ + Panel that displays information about the SQL queries run while processing the request. + """ + name = 'SQL' + + def reformat_sql(self, sql): + sql = sql.replace('`,`', '`, `') + sql = sql.replace('` FROM `', '` \n FROM `') + sql = sql.replace('` WHERE ', '` \n WHERE ') + sql = sql.replace('`) WHERE ', '`) \n WHERE ') + sql = sql.replace(' ORDER BY ', ' \n ORDER BY ') + return sql + + def process_ajax(self, request): + action = request.GET.get('op') + if action == 'explain': + # XXX: loop through each sql statement to output explain? + sql = request.GET.get('sql', '').split(';')[0] + if sql.lower().startswith('select'): + if 'params' in request.GET: + params = simplejson.loads(request.GET['params']) + else: + params = [] + cursor = connection.cursor() + cursor.execute("EXPLAIN %s" % (sql,), params) + response = cursor.fetchall() + cursor.close() + context = {'explain': response, 'sql': self.reformat_sql(sql), 'params': params} + return render_to_response('debug_toolbar/panels/sql_explain.html', context) + else: + return HttpResponse('Invalid SQL', mimetype="text/plain", status_code=403) + + def process_request(self, request): + self.queries_offset = len(connection.queries) + + def process_response(self, request, response): + self.queries = connection.queries[self.queries_offset:] + self.total_time = sum(map(lambda q: float(q['time'])*1000, self.queries)) + return response + + def title(self): + return 'SQL: %.2fms (%d queries)' % (self.total_time, len(self.queries)) + + def url(self): + return '' + + def content(self): + queries = [(q['time'], q['sql'], q['raw_sql'], simplejson.dumps(q['params'])) for q in sorted(self.queries, key=lambda x: x['time'])[::-1]] + context = {'queries': queries} + return render_to_string('debug_toolbar/panels/sql.html', context) \ No newline at end of file