aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debug_toolbar/middleware.py26
-rw-r--r--debug_toolbar/models.py54
-rw-r--r--debug_toolbar/templates/debug_toolbar/base.html4
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html8
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/templates.html4
-rw-r--r--debug_toolbar/toolbar/loader.py5
-rw-r--r--debug_toolbar/urls.py16
-rw-r--r--docs/installation.rst122
-rw-r--r--docs/tips.rst13
-rw-r--r--example/settings.py12
-rw-r--r--tests/settings.py10
-rw-r--r--tests/test_integration.py53
-rw-r--r--tests/urls.py3
13 files changed, 164 insertions, 166 deletions
diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py
index daea751..c95cade 100644
--- a/debug_toolbar/middleware.py
+++ b/debug_toolbar/middleware.py
@@ -4,17 +4,13 @@ Debug Toolbar middleware
from __future__ import unicode_literals
-import imp
import threading
from django.conf import settings
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils.encoding import force_text
-from django.utils.importlib import import_module
-from django.utils import six
-import debug_toolbar.urls
from debug_toolbar.toolbar.loader import DebugToolbar
from debug_toolbar.utils.settings import CONFIG
@@ -55,8 +51,6 @@ class DebugToolbarMiddleware(object):
debug_toolbars = {}
def __init__(self):
- self._urlconfs = {}
-
# The method to call to decide to show the toolbar
self.show_toolbar = CONFIG['SHOW_TOOLBAR_CALLBACK'] or show_toolbar
@@ -66,26 +60,6 @@ class DebugToolbarMiddleware(object):
def process_request(self, request):
__traceback_hide__ = True # noqa
if self.show_toolbar(request):
- urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
- if isinstance(urlconf, six.string_types):
- urlconf = import_module(getattr(request, 'urlconf', settings.ROOT_URLCONF))
-
- if urlconf not in self._urlconfs:
- new_urlconf = imp.new_module('urlconf')
- new_urlconf.urlpatterns = (debug_toolbar.urls.urlpatterns +
- list(urlconf.urlpatterns))
-
- if hasattr(urlconf, 'handler403'):
- new_urlconf.handler403 = urlconf.handler403
- if hasattr(urlconf, 'handler404'):
- new_urlconf.handler404 = urlconf.handler404
- if hasattr(urlconf, 'handler500'):
- new_urlconf.handler500 = urlconf.handler500
-
- self._urlconfs[urlconf] = new_urlconf
-
- request.urlconf = self._urlconfs[urlconf]
-
toolbar = DebugToolbar(request)
for panel in toolbar.panels:
panel.enabled = panel.dom_id() not in request.COOKIES
diff --git a/debug_toolbar/models.py b/debug_toolbar/models.py
index d6b18aa..fc78874 100644
--- a/debug_toolbar/models.py
+++ b/debug_toolbar/models.py
@@ -1,21 +1,65 @@
from __future__ import unicode_literals
from django.conf import settings
+from django.conf.urls import include, patterns, url
+from django.core.urlresolvers import reverse, NoReverseMatch
from django.utils.importlib import import_module
from debug_toolbar.toolbar.loader import load_panel_classes
from debug_toolbar.middleware import DebugToolbarMiddleware
-for middleware_path in settings.MIDDLEWARE_CLASSES:
+def is_toolbar_middleware(middleware_path):
# Replace this with import_by_path in Django >= 1.6.
try:
mod_path, cls_name = middleware_path.rsplit('.', 1)
mod = import_module(mod_path)
middleware_cls = getattr(mod, cls_name)
except (AttributeError, ImportError, ValueError):
- continue
+ return
+ return issubclass(middleware_cls, DebugToolbarMiddleware)
- if issubclass(middleware_cls, DebugToolbarMiddleware):
- load_panel_classes()
- break
+
+def is_toolbar_middleware_installed():
+ return any(is_toolbar_middleware(middleware)
+ for middleware in settings.MIDDLEWARE_CLASSES)
+
+
+def prepend_to_setting(setting_name, value):
+ """Insert value at the beginning of a list or tuple setting."""
+ values = getattr(settings, setting_name)
+ # Make a list [value] or tuple (value,)
+ value = type(values)((value,))
+ setattr(settings, setting_name, value + values)
+
+
+def patch_internal_ips():
+ if not settings.INTERNAL_IPS:
+ prepend_to_setting('INTERNAL_IPS', '127.0.0.1')
+ prepend_to_setting('INTERNAL_IPS', '::1')
+
+
+def patch_middleware_classes():
+ if not is_toolbar_middleware_installed():
+ prepend_to_setting('MIDDLEWARE_CLASSES',
+ 'debug_toolbar.middleware.DebugToolbarMiddleware')
+
+
+def patch_root_urlconf():
+ try:
+ reverse('djdt:render_panel')
+ except NoReverseMatch:
+ urlconf_module = import_module(settings.ROOT_URLCONF)
+ urlconf_module.urlpatterns += patterns('', # noqa
+ url(r'^__debug__/', include('debug_toolbar.urls', namespace='djdt', app_name='djdt')),
+ )
+
+
+if settings.DEBUG:
+ patch_internal_ips()
+ patch_middleware_classes()
+ patch_root_urlconf()
+
+
+if is_toolbar_middleware_installed():
+ load_panel_classes()
diff --git a/debug_toolbar/templates/debug_toolbar/base.html b/debug_toolbar/templates/debug_toolbar/base.html
index f8bd377..4c82140 100644
--- a/debug_toolbar/templates/debug_toolbar/base.html
+++ b/debug_toolbar/templates/debug_toolbar/base.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n %}{% load url from future %}
<style type="text/css">
@media print { #djDebug {display:none;}}
</style>
@@ -9,7 +9,7 @@ if(!window.jQuery) document.write('<scr'+'ipt src="{{ STATIC_URL }}debug_toolbar
<script src="{{ STATIC_URL }}debug_toolbar/js/jquery.cookie.js"></script>
<script src="{{ STATIC_URL }}debug_toolbar/js/toolbar.js"></script>
<div id="djDebug" style="display:none;" dir="ltr"
- data-toolbar-id="{{ toolbar_id }}" data-render-panel-url="/__debug__/render_panel/"
+ data-toolbar-id="{{ toolbar_id }}" data-render-panel-url="{% url 'djdt:render_panel' %}"
{{ TOOLBAR_ROOT_TAG_ATTRS|safe }}>
<div style="display:none;" id="djDebugToolbar">
<ul id="djDebugPanelList">
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index 064413c..54babfc 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n %}{% load url from future %}
{% load debug_toolbar_utils %}
<div class="clearfix">
<ul class="stats">
@@ -47,11 +47,11 @@
<form method="post">
{{ query.form }}
- <button formaction="/__debug__/sql_select/" class="remoteCall">Sel</button>
- <button formaction="/__debug__/sql_explain/" class="remoteCall">Expl</button>
+ <button formaction="{% url 'djdt:sql_select' %}" class="remoteCall">Sel</button>
+ <button formaction="{% url 'djdt:sql_explain' %}" class="remoteCall">Expl</button>
{% ifequal query.engine 'mysql' %}
- <button formaction="/__debug__/sql_profile/" class="remoteCall">Prof</button>
+ <button formaction="{% url 'djdt:sql_profile' %}" class="remoteCall">Prof</button>
{% endifequal %}
</form>
{% endif %}
diff --git a/debug_toolbar/templates/debug_toolbar/panels/templates.html b/debug_toolbar/templates/debug_toolbar/panels/templates.html
index 7e44a46..5cbb742 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/templates.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/templates.html
@@ -1,4 +1,4 @@
-{% load i18n %}
+{% load i18n %}{% load url from future %}
<h4>{% blocktrans count template_dirs|length as template_count %}Template path{% plural %}Template paths{% endblocktrans %}</h4>
{% if template_dirs %}
<ol>
@@ -14,7 +14,7 @@
{% if templates %}
<dl>
{% for template in templates %}
- <dt><strong><a class="remoteCall toggleTemplate" href="/__debug__/template_source/?template={{ template.template.name }}">{{ template.template.name|addslashes }}</a></strong></dt>
+ <dt><strong><a class="remoteCall toggleTemplate" href="{% url 'djdt:template_source' %}?template={{ template.template.name }}">{{ template.template.name|addslashes }}</a></strong></dt>
<dd><samp>{{ template.template.origin_name|addslashes }}</samp></dd>
{% if template.context %}
<dd>
diff --git a/debug_toolbar/toolbar/loader.py b/debug_toolbar/toolbar/loader.py
index de4aa93..870eec3 100644
--- a/debug_toolbar/toolbar/loader.py
+++ b/debug_toolbar/toolbar/loader.py
@@ -18,13 +18,10 @@ class DebugToolbar(object):
self.request = request
self._panels = SortedDict()
base_url = self.request.META.get('SCRIPT_NAME', '')
- self.config = {
- 'MEDIA_URL': '%s/__debug__/m/' % base_url,
- }
+ self.config = {}
self.config.update(CONFIG)
self.template_context = {
'BASE_URL': base_url, # for backwards compatibility
- 'DEBUG_TOOLBAR_MEDIA_URL': self.config['MEDIA_URL'],
'STATIC_URL': settings.STATIC_URL,
'TOOLBAR_ROOT_TAG_ATTRS': self.config['ROOT_TAG_ATTRS'],
}
diff --git a/debug_toolbar/urls.py b/debug_toolbar/urls.py
index 05ef245..860187a 100644
--- a/debug_toolbar/urls.py
+++ b/debug_toolbar/urls.py
@@ -1,20 +1,18 @@
"""
URLpatterns for the debug toolbar.
-These should not be loaded explicitly; the debug toolbar middleware will patch
-this into the urlconf for the request.
+The debug toolbar middleware will monkey-patch them into the default urlconf
+if they aren't explicitly included.
"""
from __future__ import unicode_literals
from django.conf.urls import patterns, url
-_PREFIX = '__debug__'
-
urlpatterns = patterns('debug_toolbar.views', # noqa
- url(r'^%s/render_panel/$' % _PREFIX, 'render_panel', name='render_panel'),
- url(r'^%s/sql_select/$' % _PREFIX, 'sql_select', name='sql_select'),
- url(r'^%s/sql_explain/$' % _PREFIX, 'sql_explain', name='sql_explain'),
- url(r'^%s/sql_profile/$' % _PREFIX, 'sql_profile', name='sql_profile'),
- url(r'^%s/template_source/$' % _PREFIX, 'template_source', name='template_source'),
+ url(r'^render_panel/$', 'render_panel', name='render_panel'),
+ url(r'^sql_select/$', 'sql_select', name='sql_select'),
+ url(r'^sql_explain/$', 'sql_explain', name='sql_explain'),
+ url(r'^sql_profile/$', 'sql_profile', name='sql_profile'),
+ url(r'^template_source/$', 'template_source', name='template_source'),
)
diff --git a/docs/installation.rst b/docs/installation.rst
index 32483df..514548a 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -1,66 +1,102 @@
Installation
============
-#. The recommended way to install the Debug Toolbar is via pip_::
+Getting the code
+----------------
- $ pip install django-debug-toolbar
+The recommended way to install the Debug Toolbar is via pip_::
- If you aren't familiar with pip, you may also obtain a copy of the
- ``debug_toolbar`` directory and add it to your Python path.
+ $ pip install django-debug-toolbar
- .. _pip: http://www.pip-installer.org/
+If you aren't familiar with pip, you may also obtain a copy of the
+``debug_toolbar`` directory and add it to your Python path.
+.. _pip: http://www.pip-installer.org/
- To test an upcoming release, you can install the `in-development version
- <http://github.com/django-debug-toolbar/django-debug-toolbar/tarball/master#egg=django-debug-toolbar-dev>`_
- instead with the following command::
+To test an upcoming release, you can install the `in-development version
+<http://github.com/django-debug-toolbar/django-debug-toolbar/tarball/master#egg=django-debug-toolbar-dev>`_
+instead with the following command::
- $ pip install django-debug-toolbar==dev
+ $ pip install django-debug-toolbar==dev
-#. Add the following middleware to your project's ``settings.py`` file::
+Quick setup
+-----------
- MIDDLEWARE_CLASSES = (
- # ...
- 'debug_toolbar.middleware.DebugToolbarMiddleware',
- # ...
- )
+Add ``debug_toolbar`` to your ``INSTALLED_APPS`` setting::
- Tying into middleware allows each panel to be instantiated on request and
- rendering to happen on response.
+ INSTALLED_APPS = (
+ # ...
+ 'debug_toolbar',
+ )
- The order of ``MIDDLEWARE_CLASSES`` is important. You should include the
- Debug Toolbar middleware as early as possible in the list. However, it must
- come after any other middleware that encodes the response's content, such
- as ``GZipMiddleware``.
+For a simple Django project, that's all you need!
- .. note::
+The Debug Toolbar will automatically adjust a few settings when you start the
+development server. This happens only when the ``DEBUG`` setting is ``True``.
- The debug toolbar will only display itself if the mimetype of the
- response is either ``text/html`` or ``application/xhtml+xml`` and
- contains a closing ``</body>`` tag.
+If the automatic setup doesn't work for your project, if you want to learn
+what it does, or if you prefer defining your settings explicitly, read below.
- .. note ::
+.. note::
- Be aware of middleware ordering and other middleware that may intercept
- requests and return responses. Putting the debug toolbar middleware
- *after* the Flatpage middleware, for example, means the toolbar will not
- show up on flatpages.
+ The automatic setup relies on ``debug_toolbar.models`` being imported when
+ the server starts. Django doesn't provide a better hook to execute code
+ during the start-up sequence. This works with Django's built-in
+ development server ``runserver`` because it validates models before
+ serving requests. You should use the explicit setup with other servers.
-#. Make sure your IP is listed in the ``INTERNAL_IPS`` setting. If you are
- working locally this will be::
+Explicit setup
+--------------
- INTERNAL_IPS = ('127.0.0.1',)
+URLconf
+~~~~~~~
- .. note::
+Add the Debug Toolbar's URLs to your project's URLconf as follows::
- This is required because of the built-in requirements of the
- ``show_toolbar`` method. See below for how to define a method to
- determine your own logic for displaying the toolbar.
+ from django.conf import settings
+ from django.conf.urls import include, patterns, url
-#. Add ``debug_toolbar`` to your ``INSTALLED_APPS`` setting so Django can
- find the template files associated with the Debug Toolbar::
+ if settings.DEBUG:
+ urlpatterns += patterns('',
+ url(r'^__debug__/', include('debug_toolbar.urls', namespace='djdt', app_name='djdt')),
+ )
- INSTALLED_APPS = (
- # ...
- 'debug_toolbar',
- )
+This example uses the ``__debug__`` prefix, but you can use any prefix that
+doesn't clash with your application's URLs.
+
+It is mandatory to use the ``djdt`` namespace as shown above. This avoids
+conflicts when reversing URLs by name.
+
+If the URLs aren't included in your root URLconf, the Debug Toolbar
+automatically appends them.
+
+Middleware
+~~~~~~~~~~
+
+The Debug Toolbar is mostly implemented in a middleware. Enable it in your
+settings module as follows::
+
+ MIDDLEWARE_CLASSES = (
+ # ...
+ 'debug_toolbar.middleware.DebugToolbarMiddleware',
+ # ...
+ )
+
+The order of ``MIDDLEWARE_CLASSES`` is important. You should include the Debug
+Toolbar middleware as early as possible in the list. However, it must come
+after any other middleware that encodes the response's content, such as
+``GZipMiddleware``.
+
+If ``MIDDLEWARE_CLASSES`` doesn't contain the middleware, the Debug Toolbar
+automatically adds it the beginning of the list.
+
+Internal IPs
+~~~~~~~~~~~~
+
+The Debug Toolbar is shown only if your IP is listed in the ``INTERNAL_IPS``
+setting. (You can change this logic with the ``SHOW_TOOLBAR_CALLBACK``
+option.) For local development, you should add ``'127.0.0.1'`` to
+``INTERNAL_IPS``.
+
+If ``INTERNAL_IPS`` is empty, the Debug Toolbar automatically sets it to
+``'127.0.0.1'`` and ``'::1'``.
diff --git a/docs/tips.rst b/docs/tips.rst
index 5de4ec3..d92e5ab 100644
--- a/docs/tips.rst
+++ b/docs/tips.rst
@@ -1,6 +1,19 @@
Tips
====
+The toolbar isn't displayed!
+----------------------------
+
+The Debug Toolbar will only display itself if the mimetype of the response is
+either ``text/html`` or ``application/xhtml+xml`` and contains a closing
+``</body>`` tag.
+
+Be aware of middleware ordering and other middleware that may intercept
+requests and return responses. Putting the debug toolbar middleware *after*
+the Flatpage middleware, for example, means the toolbar will not show up on
+flatpages.
+
+
Performance considerations
--------------------------
diff --git a/example/settings.py b/example/settings.py
index ce1f8e2..1eba309 100644
--- a/example/settings.py
+++ b/example/settings.py
@@ -10,8 +10,6 @@ SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
DEBUG = True
-INTERNAL_IPS = ['127.0.0.1', '::1']
-
TEMPLATE_DEBUG = True
@@ -27,16 +25,6 @@ INSTALLED_APPS = (
'debug_toolbar',
)
-MIDDLEWARE_CLASSES = (
- 'debug_toolbar.middleware.DebugToolbarMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
-)
-
ROOT_URLCONF = 'example.urls'
STATIC_URL = '/static/'
diff --git a/tests/settings.py b/tests/settings.py
index d21e9e4..a41b5a7 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -8,12 +8,12 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__))
SECRET_KEY = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
-INTERNAL_IPS = ['127.0.0.1', '::1']
+INTERNAL_IPS = ['127.0.0.1']
# Application definition
-INSTALLED_APPS = (
+INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@@ -22,9 +22,9 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'debug_toolbar',
'tests',
-)
+]
-MIDDLEWARE_CLASSES = (
+MIDDLEWARE_CLASSES = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -32,7 +32,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
-)
+]
ROOT_URLCONF = 'tests.urls'
diff --git a/tests/test_integration.py b/tests/test_integration.py
index a80f50c..412b14b 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -6,7 +6,6 @@ from xml.etree import ElementTree as ET
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings
-from django.utils import six
from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
from debug_toolbar.panels.request_vars import RequestVarsDebugPanel
@@ -34,58 +33,6 @@ class DebugToolbarTestCase(BaseTestCase):
with self.settings(INTERNAL_IPS=[]):
self.assertFalse(show_toolbar(self.request))
- def test_request_urlconf_string(self):
- request = rf.get('/')
- request.urlconf = 'tests.urls'
- middleware = DebugToolbarMiddleware()
-
- middleware.process_request(request)
-
- self.assertFalse(isinstance(request.urlconf, six.string_types))
-
- patterns = request.urlconf.urlpatterns
- self.assertTrue(hasattr(patterns[1], '_callback_str'))
- self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql')
-
- def test_request_urlconf_string_per_request(self):
- request = rf.get('/')
- request.urlconf = 'debug_toolbar.urls'
- middleware = DebugToolbarMiddleware()
-
- middleware.process_request(request)
- request.urlconf = 'tests.urls'
- middleware.process_request(request)
-
- self.assertFalse(isinstance(request.urlconf, six.string_types))
-
- patterns = request.urlconf.urlpatterns
- self.assertTrue(hasattr(patterns[1], '_callback_str'))
- self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql')
-
- def test_request_urlconf_module(self):
- request = rf.get('/')
- request.urlconf = __import__('tests.urls').urls
- middleware = DebugToolbarMiddleware()
-
- middleware.process_request(request)
-
- self.assertFalse(isinstance(request.urlconf, six.string_types))
-
- patterns = request.urlconf.urlpatterns
- self.assertTrue(hasattr(patterns[1], '_callback_str'))
- self.assertEqual(patterns[-1]._callback_str, 'tests.views.execute_sql')
-
- def test_tuple_urlconf(self):
- request = rf.get('/')
- urls = __import__('tests.urls').urls
- urls.urlpatterns = tuple(urls.urlpatterns)
- request.urlconf = urls
- middleware = DebugToolbarMiddleware()
-
- middleware.process_request(request)
-
- self.assertFalse(isinstance(request.urlconf, six.string_types))
-
def _resolve_stats(self, path):
# takes stats from RequestVars panel
self.request.path = path
diff --git a/tests/urls.py b/tests/urls.py
index 977084b..d4417a1 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
-from django.conf.urls import patterns, url
+from django.conf.urls import include, patterns, url
from django.contrib import admin
from .models import NonAsciiRepr
@@ -18,4 +18,5 @@ urlpatterns = patterns('tests.views', # noqa
url(r'^non_ascii_request/$', 'regular_view', {'title': NonAsciiRepr()}),
url(r'^new_user/$', 'new_user'),
url(r'^execute_sql/$', 'execute_sql'),
+ url(r'^__debug__/', include('debug_toolbar.urls', namespace='djdt', app_name='djdt')),
)