aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Lamb2009-10-14 14:45:51 +0100
committerRob Hudson2009-11-02 12:24:42 -0800
commit3f81a95105381a0ffabc46ae6ab84d69ace89720 (patch)
treef341f27d74a6f17177de7113d69719952620fdab
parent0d544a7f2ddbde72b9fe23ce627ad82af0abad0b (diff)
downloaddjango-debug-toolbar-3f81a95105381a0ffabc46ae6ab84d69ace89720.tar.bz2
Show context where SQL query originated from template
Signed-off-by: Chris Lamb <lamby@debian.org> Signed-off-by: Rob Hudson <rob@cogit8.org>
-rw-r--r--debug_toolbar/panels/sql.py54
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html11
2 files changed, 65 insertions, 0 deletions
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
index e1a2b7d..ce43328 100644
--- a/debug_toolbar/panels/sql.py
+++ b/debug_toolbar/panels/sql.py
@@ -1,5 +1,6 @@
from datetime import datetime
import os
+import sys
import SocketServer
import traceback
@@ -7,6 +8,8 @@ import django
from django.conf import settings
from django.db import connection
from django.db.backends import util
+from django.views.debug import linebreak_iter
+from django.template import Node
from django.template.loader import render_to_string
from django.utils import simplejson
from django.utils.encoding import force_unicode
@@ -42,6 +45,40 @@ def tidy_stacktrace(strace):
trace.append((s[0], s[1], s[2], s[3]))
return trace
+def get_template_info(source, context_lines=3):
+ line = 0
+ upto = 0
+ source_lines = []
+ before = during = after = ""
+
+ origin, (start, end) = source
+ template_source = origin.reload()
+
+ for num, next in enumerate(linebreak_iter(template_source)):
+ if start >= upto and end <= next:
+ line = num
+ before = template_source[upto:start]
+ during = template_source[start:end]
+ after = template_source[end:next]
+ source_lines.append((num, template_source[upto:next]))
+ upto = next
+
+ top = max(1, line - context_lines)
+ bottom = min(len(source_lines), line + 1 + context_lines)
+
+ context = []
+ for num, content in source_lines[top:bottom]:
+ context.append({
+ 'num': num,
+ 'content': content,
+ 'highlight': (num == line),
+ })
+
+ return {
+ 'name': origin.name,
+ 'context': context,
+ }
+
class DatabaseStatTracker(util.CursorDebugWrapper):
"""
Replacement for CursorDebugWrapper which stores additional information
@@ -60,6 +97,22 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
_params = simplejson.dumps([force_unicode(x) for x in params])
except TypeError:
pass # object not JSON serializable
+
+ template_info = None
+ cur_frame = sys._getframe().f_back
+ try:
+ while cur_frame is not None:
+ if cur_frame.f_code.co_name == 'render':
+ node = cur_frame.f_locals['self']
+ if isinstance(node, Node):
+ template_info = get_template_info(node.source)
+ break
+ cur_frame = cur_frame.f_back
+ except:
+ pass
+ finally:
+ del cur_frame
+
# We keep `sql` to maintain backwards compatibility
self.db.queries.append({
'sql': self.db.ops.last_executed_query(self.cursor, sql, params),
@@ -72,6 +125,7 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
'stop_time': stop,
'is_slow': (duration > SQL_WARNING_THRESHOLD),
'is_select': sql.lower().strip().startswith('select'),
+ 'template_info': template_info,
})
util.CursorDebugWrapper = DatabaseStatTracker
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index 038deaf..331306b 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -47,6 +47,17 @@
</tr>
{% endfor %}
</table>
+ {% if query.template_info %}
+ <table>
+ {% for line in query.template_info.context %}
+ <tr>
+ <td>{{ line.num }}</td>
+ <td><pre style="font-family: monospace;{% if line.highlight %}background-color: lightgrey{% endif %}">{{ line.content }}</pre></td>
+ </tr>
+ {% endfor %}
+ </table>
+ <p><strong>{{ query.template_info.name|default:"(unknown)" }}</strong></p>
+ {% endif %}
</div>
{% endif %}
<span class="djDebugLineChart{% if query.is_slow %} djDebugLineChartWarning{% endif %}" style="width:{{ query.width_ratio }}%; left:{{ query.start_offset }}%;"></span>