aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.rst40
-rw-r--r--debug_toolbar/__init__.py0
-rw-r--r--debug_toolbar/middleware.py32
-rw-r--r--debug_toolbar/panels/__init__.py14
-rw-r--r--debug_toolbar/panels/sql.py19
-rw-r--r--debug_toolbar/panels/version.py15
-rw-r--r--debug_toolbar/toolbar/__init__.py0
-rw-r--r--debug_toolbar/toolbar/loader.py73
9 files changed, 195 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2f78cf5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..f1a0c2c
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,40 @@
+====================
+Django Debug Toolbar
+====================
+
+The Django Debug Toolbar is a configurable set of panels that display various
+debug information about the current request/response. It is a small toolbar
+that, when activated, situates itself in the top-right location of the browser
+window. When particular panels are clicked, more details about that panel's
+content are displayed.
+
+Currently, the following panels have been written and are working:
+
+- Django version
+- SQL queries including time to execute
+
+If you have ideas for other panels please let us know.
+
+Installation
+============
+
+#. Add the `debug_toolbar` directory to your Python path.
+
+#. Add the following middleware to your project's `settings.py` file:
+
+ ``'debug_toolbar.middleware.DebugToolbarMiddleware',``
+
+#. Add a tuple called `DEBUG_TOOLBAR_PANELS` to your ``settings.py`` file that
+ specifies the full Python path to the panel that you want included in the
+ Toolbar. This setting looks very much like the `MIDDLEWARE_CLASSES` setting.
+ For example::
+
+ DEBUG_TOOLBAR_PANELS = (
+ 'debug_toolbar.panels.version.VersionDebugPanel',
+ 'debug_toolbar.panels.sql.SQLDebugPanel',
+ )
+
+TODO
+====
+- Add more panels
+- Get fancy with CSS and Javascript
diff --git a/debug_toolbar/__init__.py b/debug_toolbar/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/debug_toolbar/__init__.py
diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py
new file mode 100644
index 0000000..b2e9b29
--- /dev/null
+++ b/debug_toolbar/middleware.py
@@ -0,0 +1,32 @@
+"""
+Debug Toolbar middleware
+"""
+import re
+from django.conf import settings
+from django.utils.safestring import mark_safe
+from debug_toolbar.toolbar.loader import DebugToolbar
+
+_HTML_TYPES = ('text/html', 'application/xhtml+xml')
+_END_HEAD_RE = re.compile(r'</head>', re.IGNORECASE)
+_END_BODY_RE = re.compile(r'</body>', re.IGNORECASE)
+
+class DebugToolbarMiddleware(object):
+ """
+ Middleware to set up Debug Toolbar on incoming request and render toolbar
+ on outgoing response.
+ """
+ def __init__(self):
+ self.debug_toolbar = None
+
+ def process_request(self, request):
+ if settings.DEBUG:
+ self.debug_toolbar = DebugToolbar()
+ self.debug_toolbar.load_panels()
+ return None
+
+ def process_response(self, request, response):
+ if settings.DEBUG:
+ if response['Content-Type'].split(';')[0] in _HTML_TYPES:
+ #response.content = _END_HEAD_RE.sub(mark_safe(self.debug_toolbar.render_styles() + "%s" % match.group()), response.content)
+ response.content = _END_BODY_RE.sub(mark_safe(self.debug_toolbar.render_toolbar() + '</body>'), response.content)
+ return response
diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py
new file mode 100644
index 0000000..2454c56
--- /dev/null
+++ b/debug_toolbar/panels/__init__.py
@@ -0,0 +1,14 @@
+"""Base DebugPanel class"""
+
+class DebugPanel(object):
+ """
+ Base class for debug panels.
+ """
+ def title(self):
+ raise NotImplementedError
+
+ def url(self):
+ raise NotImplementedError
+
+ def content(self):
+ raise NotImplementedError
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
new file mode 100644
index 0000000..6c180d7
--- /dev/null
+++ b/debug_toolbar/panels/sql.py
@@ -0,0 +1,19 @@
+from debug_toolbar.panels import DebugPanel
+
+class SQLDebugPanel(DebugPanel):
+ """
+ Panel that displays information about the SQL queries run while processing the request.
+ """
+ def title(self):
+ return 'SQL Queries'
+
+ def url(self):
+ return ''
+
+ def content(self):
+ from django.db import connection
+ query_info = []
+ for q in connection.queries:
+ query_info.append('<dt>%s</dt><dd>%s</dd>' % (q['time'], q['sql']))
+ return '<dl>%s</dl>' % (''.join(query_info))
+
diff --git a/debug_toolbar/panels/version.py b/debug_toolbar/panels/version.py
new file mode 100644
index 0000000..63c44b0
--- /dev/null
+++ b/debug_toolbar/panels/version.py
@@ -0,0 +1,15 @@
+import django
+from debug_toolbar.panels import DebugPanel
+
+class VersionDebugPanel(DebugPanel):
+ """
+ Panel that displays the Django version.
+ """
+ def title(self):
+ return 'Version'
+
+ def url(self):
+ return ''
+
+ def content(self):
+ return django.get_version()
diff --git a/debug_toolbar/toolbar/__init__.py b/debug_toolbar/toolbar/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/debug_toolbar/toolbar/__init__.py
diff --git a/debug_toolbar/toolbar/loader.py b/debug_toolbar/toolbar/loader.py
new file mode 100644
index 0000000..4c3efa2
--- /dev/null
+++ b/debug_toolbar/toolbar/loader.py
@@ -0,0 +1,73 @@
+"""
+The main DebugToolbar class that loads and renders the Toolbar.
+"""
+class DebugToolbar(object):
+
+ def __init__(self):
+ self.panels = []
+ self.panel_list = []
+ self.content_list = []
+
+ def load_panels(self):
+ """
+ Populate debug panel lists from settings.DEBUG_TOOLBAR_PANELS.
+ """
+ from django.conf import settings
+ from django.core import exceptions
+
+ for panel_path in settings.DEBUG_TOOLBAR_PANELS:
+ try:
+ dot = panel_path.rindex('.')
+ except ValueError:
+ raise exceptions.ImproperlyConfigured, '%s isn\'t a debug panel module' % panel_path
+ panel_module, panel_classname = panel_path[:dot], panel_path[dot+1:]
+ try:
+ mod = __import__(panel_module, {}, {}, [''])
+ except ImportError, e:
+ raise exceptions.ImproperlyConfigured, 'Error importing debug panel %s: "%s"' % (panel_module, e)
+ try:
+ panel_class = getattr(mod, panel_classname)
+ except AttributeError:
+ raise exceptions.ImproperlyConfigured, 'Toolbar Panel module "%s" does not define a "%s" class' % (panel_module, panel_classname)
+
+ try:
+ panel_instance = panel_class()
+ except:
+ continue # Some problem loading panel
+
+ self.panels.append(panel_instance)
+
+ def render_panels(self):
+ """
+ Renders each panel.
+ """
+ for panel in self.panels:
+ div_id = 'djDebug%sPanel' % (panel.title().replace(' ', ''))
+ self.panel_list.append('<li><a title="%(title)s" href="%(url)s">%(title)s</a></li>' % ({
+ 'title': panel.title(),
+ 'url': panel.url() or '#',
+ }))
+ self.content_list.append('<div id="%(div_id)s" class="panelContent"><h1>%(title)s</h1>%(content)s</div>' % ({
+ 'div_id': div_id,
+ 'title': panel.title(),
+ 'content': panel.content(),
+ }))
+
+ def render_toolbar(self):
+ """
+ Renders the overall Toolbar with panels inside.
+ """
+ self.render_panels()
+ template = """
+ <div id="djDebugToolbar">
+ <ul id="djDebugPanelList">
+ %(panels)s
+ </ul>
+ %(contents)s
+ </div>
+ """
+ context = {
+ 'panels': ''.join(self.panel_list),
+ 'contents': ''.join(self.content_list),
+ }
+ return template % context