aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPercy Perez-Pinedo2009-07-20 15:46:57 -0700
committerPercy Perez-Pinedo2009-07-20 15:46:57 -0700
commitb7629d5768295131c35d613dbb16d9a070474c77 (patch)
treef7557bdc972287765a0bb687c2fecf04ddd0718f
parent073ab2c8255ebc310a54e9f937b4b17f94f7eac2 (diff)
parent4dc0710b6a5eedec0448909f6b90e55a4f3555d4 (diff)
downloaddjango-debug-toolbar-b7629d5768295131c35d613dbb16d9a070474c77.tar.bz2
removing trans so we can merge for now
-rw-r--r--README.rst58
-rw-r--r--debug_toolbar/__init__.py2
-rw-r--r--debug_toolbar/media/debug_toolbar/Makefile (renamed from debug_toolbar/media/Makefile)1
-rw-r--r--debug_toolbar/media/debug_toolbar/jquery.cookie.js96
-rw-r--r--debug_toolbar/media/debug_toolbar/jquery.js (renamed from debug_toolbar/media/jquery.js)0
-rw-r--r--debug_toolbar/media/debug_toolbar/toolbar.css (renamed from debug_toolbar/media/toolbar.css)27
-rw-r--r--debug_toolbar/media/debug_toolbar/toolbar.js105
-rw-r--r--debug_toolbar/media/debug_toolbar/toolbar.min.css1
-rw-r--r--debug_toolbar/media/debug_toolbar/toolbar.min.js1
-rw-r--r--debug_toolbar/media/toolbar.js66
-rw-r--r--debug_toolbar/media/toolbar.min.css1
-rw-r--r--debug_toolbar/media/toolbar.min.js1
-rw-r--r--debug_toolbar/middleware.py21
-rw-r--r--debug_toolbar/panels/signals.py79
-rw-r--r--debug_toolbar/panels/sql.py39
-rw-r--r--debug_toolbar/panels/template.py12
-rw-r--r--debug_toolbar/templates/debug_toolbar/base.html18
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/headers.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/logger.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/request_vars.html6
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/settings_vars.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/signals.html19
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql.html30
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql_explain.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql_profile.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/sql_select.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/timer.html2
-rw-r--r--debug_toolbar/templates/debug_toolbar/redirect.html2
-rw-r--r--debug_toolbar/toolbar/loader.py5
-rw-r--r--debug_toolbar/urls.py12
-rw-r--r--debug_toolbar/views.py19
-rw-r--r--setup.py2
32 files changed, 518 insertions, 119 deletions
diff --git a/README.rst b/README.rst
index 6db6ba6..c80e005 100644
--- a/README.rst
+++ b/README.rst
@@ -15,7 +15,7 @@ Currently, the following panels have been written and are working:
- GET/POST/cookie/session variable display
- Templates and context used, and their template paths
- SQL queries including time to execute and links to EXPLAIN each query
-- Cache stats
+- List of signals, their args and receivers
- Logging output via Python's built-in logging module
If you have ideas for other panels please let us know.
@@ -36,17 +36,30 @@ Installation
must come after any other middleware that encodes the response's content
(such as GZipMiddleware).
+ Note: 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.
+
#. Make sure your IP is listed in the `INTERNAL_IPS` setting. If you are
working locally this will be:
INTERNAL_IPS = ('127.0.0.1',)
+ Note: 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.
+
#. Add `debug_toolbar` to your `INSTALLED_APPS` setting so Django can find the
- the template files associated with the Debug Toolbar.
-
+ template files associated with the Debug Toolbar.
+
Alternatively, add the path to the debug toolbar templates
(``'path/to/debug_toolbar/templates'`` to your ``TEMPLATE_DIRS`` setting.)
+Configuration
+=============
+
+The debug toolbar has two settings that can be set in `settings.py`:
+
#. Optional: 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`
@@ -60,14 +73,45 @@ Installation
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
'debug_toolbar.panels.template.TemplateDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
- 'debug_toolbar.panels.cache.CacheDebugPanel',
+ 'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
)
You can change the ordering of this tuple to customize the order of the
- panels you want to display. And you can include panels that you have created
- or that are specific to your project.
+ panels you want to display, or add/remove panels. If you have custom panels
+ you can include them in this way -- just provide the full Python path to
+ your panel.
+
+#. Optional: There are a few configuration options to the debug toolbar that
+ can be placed in a dictionary:
+
+ * `INTERCEPT_REDIRECTS`: If set to True (default), the debug toolbar will
+ show an intermediate page upon redirect so you can view any debug
+ information prior to redirecting. This page will provide a link to the
+ redirect destination you can follow when ready. If set to False, redirects
+ will proceed as normal.
+
+ * `SHOW_TOOLBAR_CALLBACK`: If not set or set to None, the debug_toolbar
+ middleware will use its built-in show_toolbar method for determining whether
+ the toolbar should show or not. The default checks are that DEBUG must be
+ set to True and the IP of the request must be in INTERNAL_IPS. You can
+ provide your own method for displaying the toolbar which contains your
+ custom logic. This method should return True or False.
+
+ * `EXTRA_SIGNALS`: An array of custom signals that might be in your project,
+ defined as the python path to the signal.
+
+ Example configuration::
+
+ def custom_show_toolbar(request):
+ return True # Always show toolbar, for example purposes only.
+
+ DEBUG_TOOLBAR_CONFIG = {
+ 'INTERCEPT_REDIRECTS': False,
+ 'SHOW_TOOLBAR_CALLBACK': custom_show_toolbar,
+ 'EXTRA_SIGNALS': ['myproject.signals.MySignal'],
+ }
TODOs and BUGS
==============
-See: http://code.google.com/p/django-debug-toolbar/issues/list
+See: http://github.com/robhudson/django-debug-toolbar/issues
diff --git a/debug_toolbar/__init__.py b/debug_toolbar/__init__.py
index 9603d9e..e2fa70b 100644
--- a/debug_toolbar/__init__.py
+++ b/debug_toolbar/__init__.py
@@ -1,2 +1,2 @@
-VERSION = (0, 0, 1)
+VERSION = (0, 7, 0)
__version__ = '.'.join(map(str, VERSION))
diff --git a/debug_toolbar/media/Makefile b/debug_toolbar/media/debug_toolbar/Makefile
index 7f8f2b2..a2d6abb 100644
--- a/debug_toolbar/media/Makefile
+++ b/debug_toolbar/media/debug_toolbar/Makefile
@@ -3,6 +3,7 @@ all: compress_js compress_css
compress_js:
java -jar ~/bin/yuicompressor.jar toolbar.js > toolbar.min.js
+ java -jar ~/bin/yuicompressor.jar jquery.cookie.js >> toolbar.min.js
compress_css:
java -jar ~/bin/yuicompressor.jar --type css toolbar.css > toolbar.min.css
diff --git a/debug_toolbar/media/debug_toolbar/jquery.cookie.js b/debug_toolbar/media/debug_toolbar/jquery.cookie.js
new file mode 100644
index 0000000..6df1fac
--- /dev/null
+++ b/debug_toolbar/media/debug_toolbar/jquery.cookie.js
@@ -0,0 +1,96 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+/**
+ * Create a cookie with the given name and value and other optional parameters.
+ *
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Set the value of a cookie.
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
+ * @desc Create a cookie with all available options.
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Create a session cookie.
+ * @example $.cookie('the_cookie', null);
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
+ * used when the cookie was set.
+ *
+ * @param String name The name of the cookie.
+ * @param String value The value of the cookie.
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
+ * when the the browser exits.
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
+ * require a secure protocol (like HTTPS).
+ * @type undefined
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+
+/**
+ * Get the value of a cookie with the given name.
+ *
+ * @example $.cookie('the_cookie');
+ * @desc Get the value of a cookie.
+ *
+ * @param String name The name of the cookie.
+ * @return The value of the cookie.
+ * @type String
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl@stilbuero.de
+ */
+jQuery.cookie = function(name, value, options) {
+ if (typeof value != 'undefined') { // name and value given, set cookie
+ options = options || {};
+ if (value === null) {
+ value = '';
+ options.expires = -1;
+ }
+ var expires = '';
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
+ var date;
+ if (typeof options.expires == 'number') {
+ date = new Date();
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
+ } else {
+ date = options.expires;
+ }
+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
+ }
+ // CAUTION: Needed to parenthesize options.path and options.domain
+ // in the following expressions, otherwise they evaluate to undefined
+ // in the packed version for some reason...
+ var path = options.path ? '; path=' + (options.path) : '';
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
+ var secure = options.secure ? '; secure' : '';
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
+ } else { // only name given, get cookie
+ var cookieValue = null;
+ if (document.cookie && document.cookie != '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+ }
+}; \ No newline at end of file
diff --git a/debug_toolbar/media/jquery.js b/debug_toolbar/media/debug_toolbar/jquery.js
index 82b98e1..82b98e1 100644
--- a/debug_toolbar/media/jquery.js
+++ b/debug_toolbar/media/debug_toolbar/jquery.js
diff --git a/debug_toolbar/media/toolbar.css b/debug_toolbar/media/debug_toolbar/toolbar.css
index 2ce4226..9ef6dc3 100644
--- a/debug_toolbar/media/toolbar.css
+++ b/debug_toolbar/media/debug_toolbar/toolbar.css
@@ -4,6 +4,7 @@
margin: 0;
padding: 0;
position: static;
+ text-align: left;
}
#djDebug a {
color: #f7c757;
@@ -23,6 +24,27 @@
right:0;
}
+#djDebugToolbarHandle {
+ background: #326342;
+ height: 30px;
+ z-index: 100000000;
+ border-bottom: 2px solid #234f32;
+ position:absolute;
+ top:0;
+ left:0;
+ right:0;
+ width: 16px;
+}
+
+#djDebugToolbarHandle ul li {
+ padding: 3px 0px 0px 3px;
+}
+
+#djDebugToolbarHandle ul li a {
+ font-size: 16px;
+ font-weight: bold;
+}
+
#djDebugToolbar ul {
margin: 0;
padding: 0;
@@ -65,6 +87,9 @@
background-color: #ffffff;
}
+#djDebug tr.djDebugOdd pre {
+ background-color: #eeeeee;
+}
#djDebug .panelContent {
background: #2a5738;
@@ -132,7 +157,7 @@
color: #000;
vertical-align: top;
}
-#djDebug .panelContent table tr.odd td {
+#djDebug .panelContent table tr.djDebugOdd td {
background: #eee;
}
diff --git a/debug_toolbar/media/debug_toolbar/toolbar.js b/debug_toolbar/media/debug_toolbar/toolbar.js
new file mode 100644
index 0000000..40e1a58
--- /dev/null
+++ b/debug_toolbar/media/debug_toolbar/toolbar.js
@@ -0,0 +1,105 @@
+jQuery.noConflict();
+jQuery(function($j) {
+ var COOKIE_NAME = 'dj_debug_panel';
+ $j.djDebug = function(data, klass) {
+ $j.djDebug.init();
+ }
+ $j.extend($j.djDebug, {
+ init: function() {
+ var current = null;
+ $j('#djDebugPanelList li a').click(function() {
+ if (!this.className) {
+ return false;
+ }
+ current = $j('#djDebug #' + this.className);
+ if (current.is(':visible')) {
+ $j(document).trigger('close.djDebug');
+ } else {
+ $j('.panelContent').hide();
+ current.show();
+ $j.djDebug.open();
+ }
+ return false;
+ });
+ $j('#djDebug a.close').click(function() {
+ $j(document).trigger('close.djDebug');
+ return false;
+ });
+ $j('#djDebug a.remoteCall').click(function() {
+ $j('#djDebugWindow').load(this.href, {}, function() {
+ $j('#djDebugWindow a.back').click(function() {
+ $j(this).parent().hide();
+ return false;
+ });
+ });
+ $j('#djDebugWindow').show();
+ return false;
+ });
+ $j('#djDebugTemplatePanel a.djTemplateShowContext').click(function() {
+ $j.djDebug.toggle_content($j(this).parent().next());
+ return false;
+ });
+ $j('#djDebugSQLPanel a.djSQLShowStacktrace').click(function() {
+ $j.djDebug.toggle_content($j(this).parent().next());
+ return false;
+ });
+ $j('#djHideToolBarButton').click(function() {
+ $j.djDebug.hide_toolbar(true);
+ return false;
+ });
+ $j('#djShowToolBarButton').click(function() {
+ $j.djDebug.show_toolbar();
+ return false;
+ });
+ if ($j.cookie(COOKIE_NAME)) {
+ $j.djDebug.hide_toolbar(false);
+ } else {
+ $j('#djDebugToolbar').show();
+ }
+ },
+ open: function() {
+ $j(document).bind('keydown.djDebug', function(e) {
+ if (e.keyCode == 27) {
+ $j.djDebug.close();
+ }
+ });
+ },
+ toggle_content: function(elem) {
+ if (elem.is(':visible')) {
+ elem.hide();
+ } else {
+ elem.show();
+ }
+ },
+ close: function() {
+ $j(document).trigger('close.djDebug');
+ return false;
+ },
+ hide_toolbar: function(setCookie) {
+ $j('#djDebugToolbar').hide("fast");
+ $j(document).trigger('close.djDebug');
+ $j('#djDebugToolbarHandle').show();
+ if (setCookie) {
+ $j.cookie(COOKIE_NAME, 'hide', {
+ path: '/',
+ expires: 10
+ });
+ }
+ },
+ show_toolbar: function() {
+ $j('#djDebugToolbarHandle').hide();
+ $j('#djDebugToolbar').show("fast");
+ $j.cookie(COOKIE_NAME, null, {
+ path: '/',
+ expires: -1
+ });
+ }
+ });
+ $j(document).bind('close.djDebug', function() {
+ $j(document).unbind('keydown.djDebug');
+ $j('.panelContent').hide();
+ });
+});
+jQuery(function() {
+ jQuery.djDebug();
+});
diff --git a/debug_toolbar/media/debug_toolbar/toolbar.min.css b/debug_toolbar/media/debug_toolbar/toolbar.min.css
new file mode 100644
index 0000000..c172fbd
--- /dev/null
+++ b/debug_toolbar/media/debug_toolbar/toolbar.min.css
@@ -0,0 +1 @@
+#djDebug *{color:#000;float:none;margin:0;padding:0;position:static;text-align:left;}#djDebug a{color:#f7c757;}#djDebug a:hover{color:#aaa;}#djDebugToolbar{background:#326342;height:30px;z-index:100000000;border-bottom:2px solid #234f32;position:absolute;top:0;left:0;right:0;}#djDebugToolbarHandle{background:#326342;height:30px;z-index:100000000;border-bottom:2px solid #234f32;position:absolute;top:0;left:0;right:0;width:16px;}#djDebugToolbarHandle ul li{padding:3px 0 0 3px;}#djDebugToolbarHandle ul li a{font-size:16px;font-weight:bold;}#djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebugToolbar li{border-left:1px solid #487858;color:#fff;display:inline;font-size:11px;font-weight:bold;float:none;height:20px;margin:0;padding:0;line-height:30px;padding:8px 9px 9px;position:relative;width:auto;}#djDebugToolbar li:hover{background:#487858;}#djDebugToolbar li:hover a{color:#fff;}#djDebugToolbar li:last-child{border-right:1px solid #487858;}#djDebugToolbar #djDebugButton{color:#92ef3f;}#djDebug pre{background-color:#fff;}#djDebug tr.djDebugOdd pre{background-color:#eee;}#djDebug .panelContent{background:#2a5738;border-bottom:2px solid #234f32;border-top:2px solid #487858;display:none;position:absolute;margin:0;padding:10px;top:32px;width:auto;left:0;right:0;bottom:5px;color:black;z-index:1000000;overflow:auto;}#djDebug .panelContent p a,#djDebug .panelContent dl a{color:#40684c;}#djDebug .panelContent p a:hover,#djDebug .panelContent dl a:hover{color:#92EF3F;}#djDebug .panelContent h3{border-bottom:1px solid #40684c;color:#92ef3f;padding:0 0 5px;}#djDebug .panelContent p{padding:0 5px;}#djDebug .panelContent p,#djDebug .panelContent table,#djDebug .panelContent ol,#djDebug .panelContent ul,#djDebug .panelContent dl{margin:5px 0 15px;background-color:#fff;}#djDebug .panelContent table{width:100%;clear:both;}#djDebug .panelContent table a{color:#40684C;}#djDebug .panelContent table th{background-color:#9dcc49;font-weight:bold;color:#000;font-size:11px;padding:3px 7px 3px;text-align:left;cursor:pointer;border-right:1px solid #b9d977;}#djDebug .panelContent table td{padding:5px 10px;font-size:11px;background:#fff;color:#000;vertical-align:top;}#djDebug .panelContent table tr.djDebugOdd td{background:#eee;}#djDebug .panelContent .close{float:right;font-weight:bold;}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dd{margin-left:10px;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#40684C;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#40684C;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#40684C;font-weight:bold;}#djDebug .highlight .s{color:#0086d2;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#40684C;font-weight:bold;}#djDebug .highlight .na{color:#7D9029;}#djDebug .highlight .nt{color:#008000;font-weight:bold;}#djDebug .highlight .nv{color:#19177C;}#djDebug .highlight .s2{color:#BA2121;}#djDebug .highlight .cp{color:#BC7A00;} \ No newline at end of file
diff --git a/debug_toolbar/media/debug_toolbar/toolbar.min.js b/debug_toolbar/media/debug_toolbar/toolbar.min.js
new file mode 100644
index 0000000..7f8658f
--- /dev/null
+++ b/debug_toolbar/media/debug_toolbar/toolbar.min.js
@@ -0,0 +1 @@
+jQuery.noConflict();jQuery(function(b){var a="dj_debug_panel";b.djDebug=function(d,c){b.djDebug.init()};b.extend(b.djDebug,{init:function(){var c=null;b("#djDebugPanelList li a").click(function(){if(!this.className){return false}c=b("#djDebug #"+this.className);if(c.is(":visible")){b(document).trigger("close.djDebug")}else{b(".panelContent").hide();c.show();b.djDebug.open()}return false});b("#djDebug a.close").click(function(){b(document).trigger("close.djDebug");return false});b("#djDebug a.remoteCall").click(function(){b("#djDebugWindow").load(this.href,{},function(){b("#djDebugWindow a.back").click(function(){b(this).parent().hide();return false})});b("#djDebugWindow").show();return false});b("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){b.djDebug.toggle_content(b(this).parent().next());return false});b("#djDebugSQLPanel a.djSQLShowStacktrace").click(function(){b.djDebug.toggle_content(b(this).parent().next());return false});b("#djHideToolBarButton").click(function(){b.djDebug.hide_toolbar(true);return false});b("#djShowToolBarButton").click(function(){b.djDebug.show_toolbar();return false});if(b.cookie(a)){b.djDebug.hide_toolbar(false)}else{b("#djDebugToolbar").show()}},open:function(){b(document).bind("keydown.djDebug",function(c){if(c.keyCode==27){b.djDebug.close()}})},toggle_content:function(c){if(c.is(":visible")){c.hide()}else{c.show()}},close:function(){b(document).trigger("close.djDebug");return false},hide_toolbar:function(c){b("#djDebugToolbar").hide("fast");b(document).trigger("close.djDebug");b("#djDebugToolbarHandle").show();if(c){b.cookie(a,"hide",{path:"/",expires:10})}},show_toolbar:function(){b("#djDebugToolbarHandle").hide();b("#djDebugToolbar").show("fast");b.cookie(a,null,{path:"/",expires:-1})}});b(document).bind("close.djDebug",function(){b(document).unbind("keydown.djDebug");b(".panelContent").hide()})});jQuery(function(){jQuery.djDebug()});jQuery.cookie=function(b,j,m){if(typeof j!="undefined"){m=m||{};if(j===null){j="";m.expires=-1}var e="";if(m.expires&&(typeof m.expires=="number"||m.expires.toUTCString)){var f;if(typeof m.expires=="number"){f=new Date();f.setTime(f.getTime()+(m.expires*24*60*60*1000))}else{f=m.expires}e="; expires="+f.toUTCString()}var l=m.path?"; path="+(m.path):"";var g=m.domain?"; domain="+(m.domain):"";var a=m.secure?"; secure":"";document.cookie=[b,"=",encodeURIComponent(j),e,l,g,a].join("")}else{var d=null;if(document.cookie&&document.cookie!=""){var k=document.cookie.split(";");for(var h=0;h<k.length;h++){var c=jQuery.trim(k[h]);if(c.substring(0,b.length+1)==(b+"=")){d=decodeURIComponent(c.substring(b.length+1));break}}}return d}}; \ No newline at end of file
diff --git a/debug_toolbar/media/toolbar.js b/debug_toolbar/media/toolbar.js
deleted file mode 100644
index 455a2fc..0000000
--- a/debug_toolbar/media/toolbar.js
+++ /dev/null
@@ -1,66 +0,0 @@
-var _$ = window.$;
-jQuery.noConflict();
-jQuery(function($) {
- $.djDebug = function(data, klass) {
- $.djDebug.init();
- }
- $.extend($.djDebug, {
- init: function() {
- var current = null;
- $('#djDebugPanelList li a').click(function() {
- current = $('#djDebug #' + this.className);
- if (current.is(':visible')) {
- $(document).trigger('close.djDebug');
- } else {
- $('.panelContent').hide();
- current.show();
- $.djDebug.open();
- }
- return false;
- });
- $('#djDebug a.close').click(function() {
- $(document).trigger('close.djDebug');
- return false;
- });
- $('#djDebug a.remoteCall').click(function() {
- $('#djDebugWindow').load(this.href, {}, function() {
- $('#djDebugWindow a.back').click(function() {
- $(this).parent().hide();
- return false;
- });
- });
- $('#djDebugWindow').show();
- return false;
- });
- $('#djDebugTemplatePanel a.djTemplateShowContext').click(function() {
- $.djDebug.toggle_content($(this).parent().next());
- });
- },
- open: function() {
- $(document).bind('keydown.djDebug', function(e) {
- if (e.keyCode == 27) {
- $.djDebug.close();
- }
- });
- },
- toggle_content: function(elem) {
- if (elem.is(':visible')) {
- elem.hide();
- } else {
- elem.show();
- }
- },
- close: function() {
- $(document).trigger('close.djDebug');
- return false;
- }
- });
- $(document).bind('close.djDebug', function() {
- $(document).unbind('keydown.djDebug');
- $('.panelContent').hide();
- });
-});
-jQuery(function() {
- jQuery.djDebug();
-});
-$ = _$;
diff --git a/debug_toolbar/media/toolbar.min.css b/debug_toolbar/media/toolbar.min.css
deleted file mode 100644
index bb7c034..0000000
--- a/debug_toolbar/media/toolbar.min.css
+++ /dev/null
@@ -1 +0,0 @@
-#djDebug *{color:#000;float:none;margin:0;padding:0;position:static;}#djDebug a{color:#f7c757;}#djDebug a:hover{color:#aaa;}#djDebugToolbar{background:#326342;height:30px;z-index:100000000;border-bottom:2px solid #234f32;position:absolute;top:0;left:0;right:0;}#djDebugToolbar ul{margin:0;padding:0;list-style:none;}#djDebugToolbar li{border-left:1px solid #487858;color:#fff;display:inline;font-size:11px;font-weight:bold;float:none;height:20px;margin:0;padding:0;line-height:30px;padding:8px 9px 9px;position:relative;width:auto;}#djDebugToolbar li:hover{background:#487858;}#djDebugToolbar li:hover a{color:#fff;}#djDebugToolbar li:last-child{border-right:1px solid #487858;}#djDebugToolbar #djDebugButton{color:#92ef3f;}#djDebug pre{background-color:#fff;}#djDebug .panelContent{background:#2a5738;border-bottom:2px solid #234f32;border-top:2px solid #487858;display:none;position:absolute;margin:0;padding:10px;top:32px;width:auto;left:0;right:0;bottom:5px;color:black;z-index:1000000;overflow:auto;}#djDebug .panelContent p a,#djDebug .panelContent dl a{color:#40684c;}#djDebug .panelContent p a:hover,#djDebug .panelContent dl a:hover{color:#92EF3F;}#djDebug .panelContent h3{border-bottom:1px solid #40684c;color:#92ef3f;padding:0 0 5px;}#djDebug .panelContent p{padding:0 5px;}#djDebug .panelContent p,#djDebug .panelContent table,#djDebug .panelContent ol,#djDebug .panelContent ul,#djDebug .panelContent dl{margin:5px 0 15px;background-color:#fff;}#djDebug .panelContent table{width:100%;clear:both;}#djDebug .panelContent table a{color:#40684C;}#djDebug .panelContent table th{background-color:#9dcc49;font-weight:bold;color:#000;font-size:11px;padding:3px 7px 3px;text-align:left;cursor:pointer;border-right:1px solid #b9d977;}#djDebug .panelContent table td{padding:5px 10px;font-size:11px;background:#fff;color:#000;vertical-align:top;}#djDebug .panelContent table tr.odd td{background:#eee;}#djDebug .panelContent .close{float:right;font-weight:bold;}#djDebug .panelContent dt,#djDebug .panelContent dd{display:block;}#djDebug .panelContent dd{margin-left:10px;}#djDebug .highlight{color:#000;}#djDebug .highlight .err{color:#000;}#djDebug .highlight .g{color:#000;}#djDebug .highlight .k{color:#40684C;font-weight:bold;}#djDebug .highlight .o{color:#000;}#djDebug .highlight .n{color:#000;}#djDebug .highlight .mi{color:#40684C;font-weight:bold;}#djDebug .highlight .l{color:#000;}#djDebug .highlight .x{color:#000;}#djDebug .highlight .p{color:#000;}#djDebug .highlight .m{color:#40684C;font-weight:bold;}#djDebug .highlight .s{color:#0086d2;}#djDebug .highlight .w{color:#888;}#djDebug .highlight .il{color:#40684C;font-weight:bold;}#djDebug .highlight .na{color:#7D9029;}#djDebug .highlight .nt{color:#008000;font-weight:bold;}#djDebug .highlight .nv{color:#19177C;}#djDebug .highlight .s2{color:#BA2121;}#djDebug .highlight .cp{color:#BC7A00;} \ No newline at end of file
diff --git a/debug_toolbar/media/toolbar.min.js b/debug_toolbar/media/toolbar.min.js
deleted file mode 100644
index 1f8b8b5..0000000
--- a/debug_toolbar/media/toolbar.min.js
+++ /dev/null
@@ -1 +0,0 @@
-var _$=window.$;jQuery.noConflict();jQuery(function(A){A.djDebug=function(C,B){A.djDebug.init()};A.extend(A.djDebug,{init:function(){var B=null;A("#djDebugPanelList li a").click(function(){B=A("#djDebug #"+this.className);if(B.is(":visible")){A(document).trigger("close.djDebug")}else{A(".panelContent").hide();B.show();A.djDebug.open()}return false});A("#djDebug a.close").click(function(){A(document).trigger("close.djDebug");return false});A("#djDebug a.remoteCall").click(function(){A("#djDebugWindow").load(this.href,{},function(){A("#djDebugWindow a.back").click(function(){A(this).parent().hide();return false})});A("#djDebugWindow").show();return false});A("#djDebugTemplatePanel a.djTemplateShowContext").click(function(){A.djDebug.toggle_content(A(this).parent().next())})},open:function(){A(document).bind("keydown.djDebug",function(B){if(B.keyCode==27){A.djDebug.close()}})},toggle_content:function(B){if(B.is(":visible")){B.hide()}else{B.show()}},close:function(){A(document).trigger("close.djDebug");return false}});A(document).bind("close.djDebug",function(){A(document).unbind("keydown.djDebug");A(".panelContent").hide()})});jQuery(function(){jQuery.djDebug()});$=_$; \ No newline at end of file
diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py
index 8dcf454..e4d7494 100644
--- a/debug_toolbar/middleware.py
+++ b/debug_toolbar/middleware.py
@@ -1,11 +1,14 @@
"""
Debug Toolbar middleware
"""
+import os
+
from django.conf import settings
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.utils.encoding import smart_unicode
from django.conf.urls.defaults import include, patterns
+
import debug_toolbar.urls
from debug_toolbar.toolbar.loader import DebugToolbar
@@ -17,7 +20,7 @@ def replace_insensitive(string, target, replacement):
Code borrowed from: http://forums.devshed.com/python-programming-11/case-insensitive-string-replace-490921.html
"""
no_case = string.lower()
- index = no_case.find(target.lower())
+ index = no_case.rfind(target.lower())
if index >= 0:
return string[:index] + replacement + string[index + len(target):]
else: # no results so return the original string
@@ -34,11 +37,21 @@ class DebugToolbarMiddleware(object):
self.original_pattern = patterns('', ('', include(self.original_urlconf)),)
self.override_url = True
- def show_toolbar(self, request):
+ # Set method to use to decide to show toolbar
+ self.show_toolbar = self._show_toolbar # default
+ if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'):
+ show_toolbar_callback = settings.DEBUG_TOOLBAR_CONFIG.get(
+ 'SHOW_TOOLBAR_CALLBACK', None)
+ if show_toolbar_callback:
+ self.show_toolbar = show_toolbar_callback
+
+ def _show_toolbar(self, request):
if not settings.DEBUG:
return False
- if request.is_ajax():
- return False
+ if request.is_ajax() and not \
+ request.path.startswith(os.path.join('/', debug_toolbar.urls._PREFIX)):
+ # Allow ajax requests from the debug toolbar
+ return False
if not request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS:
return False
return True
diff --git a/debug_toolbar/panels/signals.py b/debug_toolbar/panels/signals.py
new file mode 100644
index 0000000..7fe382e
--- /dev/null
+++ b/debug_toolbar/panels/signals.py
@@ -0,0 +1,79 @@
+import sys
+
+from django.conf import settings
+from django.core.signals import request_started, request_finished, \
+ got_request_exception
+from django.db.models.signals import class_prepared, pre_init, post_init, \
+ pre_save, post_save, pre_delete, post_delete, post_syncdb
+from django.dispatch.dispatcher import WEAKREF_TYPES
+from django.template.loader import render_to_string
+
+try:
+ from django.db.backends.signals import connection_created
+except ImportError:
+ connection_created = None
+
+from debug_toolbar.panels import DebugPanel
+
+class SignalDebugPanel(DebugPanel):
+ name = "Signals"
+ has_content = True
+
+ SIGNALS = {
+ 'request_started': request_started,
+ 'request_finished': request_finished,
+ 'got_request_exception': got_request_exception,
+ 'connection_created': connection_created,
+ 'class_prepared': class_prepared,
+ 'pre_init': pre_init,
+ 'post_init': post_init,
+ 'pre_save': pre_save,
+ 'post_save': post_save,
+ 'pre_delete': pre_delete,
+ 'post_delete': post_delete,
+ 'post_syncdb': post_syncdb,
+ }
+
+ def title(self):
+ return "Signals"
+
+ def url(self):
+ return ''
+
+ def signals(self):
+ signals = self.SIGNALS.copy()
+ if hasattr(settings, 'DEBUG_TOOLBAR_CONFIG'):
+ extra_signals = settings.DEBUG_TOOLBAR_CONFIG.get('EXTRA_SIGNALS', [])
+ else:
+ extra_signals = []
+ for signal in extra_signals:
+ parts = signal.split('.')
+ path = '.'.join(parts[:-1])
+ __import__(path)
+ signals[parts[-1]] = getattr(sys.modules[path], parts[-1])
+ return signals
+ signals = property(signals)
+
+ def content(self):
+ signals = []
+ keys = self.signals.keys()
+ keys.sort()
+ for name in keys:
+ signal = self.signals[name]
+ if signal is None:
+ continue
+ receivers = []
+ for (receiverkey, r_senderkey), receiver in signal.receivers:
+ if isinstance(receiver, WEAKREF_TYPES):
+ receiver = receiver()
+ if receiver is None:
+ continue
+ if getattr(receiver, 'im_self', None) is not None:
+ text = "method %s on %s object" % (receiver.__name__, receiver.im_self.__class__.__name__)
+ elif getattr(receiver, 'im_class', None) is not None:
+ text = "method %s on %s" % (receiver.__name__, receiver.im_class.__name__)
+ else:
+ text = "function %s" % receiver.__name__
+ receivers.append(text)
+ signals.append((name, signal, receivers))
+ return render_to_string('debug_toolbar/panels/signals.html', {'signals': signals})
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
index 7396c3a..d3ac7f3 100644
--- a/debug_toolbar/panels/sql.py
+++ b/debug_toolbar/panels/sql.py
@@ -1,5 +1,8 @@
+import os
+import SocketServer
import time
-from debug_toolbar.panels import DebugPanel
+import traceback
+import django
from django.conf import settings
from django.db import connection
from django.db.backends import util
@@ -7,6 +10,28 @@ from django.template.loader import render_to_string
from django.utils import simplejson
from django.utils.encoding import force_unicode
from django.utils.hashcompat import sha_constructor
+from debug_toolbar.panels import DebugPanel
+
+# Figure out some paths
+django_path = os.path.realpath(os.path.dirname(django.__file__))
+socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__))
+
+def tidy_stacktrace(strace):
+ """
+ Clean up stacktrace and remove all entries that:
+ 1. Are part of Django (except contrib apps)
+ 2. Are part of SocketServer (used by Django's dev server)
+ 3. Are the last entry (which is part of our stacktracing code)
+ """
+ trace = []
+ for s in strace[:-1]:
+ s_path = os.path.realpath(s[0])
+ if django_path in s_path and not 'django/contrib' in s_path:
+ continue
+ if socketserver_path in s_path:
+ continue
+ trace.append((s[0], s[1], s[2], s[3]))
+ return trace
class DatabaseStatTracker(util.CursorDebugWrapper):
"""
@@ -19,6 +44,7 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
return self.cursor.execute(sql, params)
finally:
stop = time.time()
+ stacktrace = tidy_stacktrace(traceback.extract_stack())
_params = ''
try:
_params = simplejson.dumps([force_unicode(x) for x in params])
@@ -31,6 +57,7 @@ class DatabaseStatTracker(util.CursorDebugWrapper):
'raw_sql': sql,
'params': _params,
'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(),
+ 'stacktrace': stacktrace,
})
util.CursorDebugWrapper = DatabaseStatTracker
@@ -71,13 +98,15 @@ class SQLDebugPanel(DebugPanel):
return render_to_string('debug_toolbar/panels/sql.html', context)
def reformat_sql(sql):
- sql = sql.replace('`,`', '`, `')
+ sql = sql.replace(',', ', ')
sql = sql.replace('SELECT ', 'SELECT\n\t')
- sql = sql.replace('` FROM ', '`\nFROM\n\t')
+ sql = sql.replace(' FROM ', '\nFROM\n\t')
sql = sql.replace(' WHERE ', '\nWHERE\n\t')
- sql = sql.replace(' INNER JOIN ', '\nINNER JOIN\n\t')
- sql = sql.replace(' LEFT OUTER JOIN ', '\nLEFT OUTER JOIN\n\t')
+ sql = sql.replace(' INNER JOIN', '\n\tINNER JOIN')
+ sql = sql.replace(' LEFT OUTER JOIN' , '\n\tLEFT OUTER JOIN')
sql = sql.replace(' ORDER BY ', '\nORDER BY\n\t')
+ sql = sql.replace(' HAVING ', '\nHAVING\n\t')
+ sql = sql.replace(' GROUP BY ', '\nGROUP BY\n\t')
# Use Pygments to highlight SQL if it's available
try:
from pygments import highlight
diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py
index fa85cb8..7dc7b06 100644
--- a/debug_toolbar/panels/template.py
+++ b/debug_toolbar/panels/template.py
@@ -48,11 +48,15 @@ class TemplateDebugPanel(DebugPanel):
return ''
def process_request(self, request):
- self.context_processors = dict(
- [("%s.%s" % (k.__module__, k.__name__), pformat(k(request))) for k in get_standard_processors()]
- )
+ self.request = request
def content(self):
+ context_processors = dict(
+ [
+ ("%s.%s" % (k.__module__, k.__name__),
+ pformat(k(self.request))) for k in get_standard_processors()
+ ]
+ )
template_context = []
for i, d in enumerate(self.templates):
info = {}
@@ -73,6 +77,6 @@ class TemplateDebugPanel(DebugPanel):
context = {
'templates': template_context,
'template_dirs': [normpath(x) for x in settings.TEMPLATE_DIRS],
- 'context_processors': self.context_processors,
+ 'context_processors': context_processors,
}
return render_to_string('debug_toolbar/panels/templates.html', context)
diff --git a/debug_toolbar/templates/debug_toolbar/base.html b/debug_toolbar/templates/debug_toolbar/base.html
index fca6256..66d126e 100644
--- a/debug_toolbar/templates/debug_toolbar/base.html
+++ b/debug_toolbar/templates/debug_toolbar/base.html
@@ -1,18 +1,29 @@
{% load i18n %}
<script type="text/javascript" charset="utf-8">
+ // When jQuery is sourced, it's going to overwrite whatever might be in the
+ // '$' variable, so store a reference of it in a temporary variable...
+ var _$ = window.$;
if (typeof jQuery == 'undefined') {
var jquery_url = '{{ BASE_URL }}/__debug__/m/jquery.js';
document.write(unescape('%3Cscript src="' + jquery_url + '" type="text/javascript"%3E%3C/script%3E'));
}
</script>
<script type="text/javascript" src="{{ BASE_URL }}/__debug__/m/toolbar.min.js"></script>
+<script type="text/javascript" charset="utf-8">
+ // Now that jQuery is done loading, put the '$' variable back to what it was...
+ var $ = _$;
+</script>
<style type="text/css">
@import url({{ BASE_URL }}/__debug__/m/toolbar.min.css);
</style>
<div id="djDebug">
- <div id="djDebugToolbar">
+ <div style="display: none;" id="djDebugToolbar">
<ul id="djDebugPanelList">
+ {% if panels %}
+ <li><a id="djHideToolBarButton" href="#" title="Hide Toolbar">&laquo; Hide</a></li>
+ {% else %}
<li id="djDebugButton">DEBUG</li>
+ {% endif %}
{% for panel in panels %}
<li>
{% if panel.has_content %}
@@ -24,6 +35,11 @@
{% endfor %}
</ul>
</div>
+ <div style="display: none;" id="djDebugToolbarHandle">
+ <ul id="djDebugPanelList">
+ <li><a title="Show Toolbar" id="djShowToolBarButton" href="#">&raquo;</a></li>
+ </ul>
+ </div>
{% for panel in panels %}
{% if panel.has_content %}
<div id="{{ panel.dom_id }}" class="panelContent">
diff --git a/debug_toolbar/templates/debug_toolbar/panels/headers.html b/debug_toolbar/templates/debug_toolbar/panels/headers.html
index 0a1578d..dec83bf 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/headers.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/headers.html
@@ -9,7 +9,7 @@
</thead>
<tbody>
{% for key, value in headers.iteritems %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
</tr>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/logger.html b/debug_toolbar/templates/debug_toolbar/panels/logger.html
index 112cc7d..441337c 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/logger.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/logger.html
@@ -12,7 +12,7 @@
</thead>
<tbody>
{% for record in records %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ record.level }}</td>
<td>{{ record.time|date:"h:i:s m/d/Y" }}</td>
<td>{{ record.message }}</td>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/request_vars.html b/debug_toolbar/templates/debug_toolbar/panels/request_vars.html
index 751e1da..677714d 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/request_vars.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/request_vars.html
@@ -14,7 +14,7 @@
</thead>
<tbody>
{% for key, value in cookies %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
</tr>
@@ -39,7 +39,7 @@
</thead>
<tbody>
{% for key, value in session %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
</tr>
@@ -60,7 +60,7 @@
</thead>
<tbody>
{% for key, value in get %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|join:", "|escape }}</td>
</tr>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/settings_vars.html b/debug_toolbar/templates/debug_toolbar/panels/settings_vars.html
index 7b285ff..92b65cd 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/settings_vars.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/settings_vars.html
@@ -9,7 +9,7 @@
</thead>
<tbody>
{% for var in settings.items|dictsort:"0" %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ var.0 }}</td>
<td><code>{{ var.1|pprint }}</code></td>
</tr>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/signals.html b/debug_toolbar/templates/debug_toolbar/panels/signals.html
new file mode 100644
index 0000000..e9a189e
--- /dev/null
+++ b/debug_toolbar/templates/debug_toolbar/panels/signals.html
@@ -0,0 +1,19 @@
+<h3>Signals</h3>
+<table>
+ <thead>
+ <tr>
+ <th>Signal</th>
+ <th>Providing Args</th>
+ <th>Receivers</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for name, signal, receivers in signals %}
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
+ <td>{{ name|escape }}</td>
+ <td>{{ signal.providing_args|join:", " }}</td>
+ <td>{{ receivers|join:", " }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+</table>
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql.html b/debug_toolbar/templates/debug_toolbar/panels/sql.html
index 50480bf..99ce611 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql.html
@@ -3,14 +3,15 @@
<table>
<thead>
<tr>
- <th>{% trans "Time" %}&nbsp;(ms)</th>
- <th>{% trans "Action" %}</th>
- <th>{% trans "Query" %}</th>
+ <th>Time&nbsp;(ms)</th>
+ <th>Action</th>
+ <th>Stacktrace</th>
+ <th>Query</th>
</tr>
</thead>
<tbody>
{% for query in queries %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ query.time|floatformat:"2" }}</td>
<td>
{% if query.params %}
@@ -21,6 +22,27 @@
{% endif %}
{% endif %}
</td>
+ <td>
+ {% if query.stacktrace %}
+ <div class="djSQLShowStacktraceDiv"><a class="djSQLShowStacktrace" href="#">Toggle Stacktrace</a></div>
+ <div class="djSQLHideStacktraceDiv" style="display:none;">
+ <table>
+ <tr>
+ <th>Line</th>
+ <th>Method</th>
+ <th>File</th>
+ </tr>
+ {% for file, line, method in query.stacktrace %}
+ <tr>
+ <td>{{ line }}</td>
+ <td><pre>{{ method|escape }}<pre></td>
+ <td><pre>{{ file|escape }}</pre></td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endif %}
+ </td>
<td class="syntax">{{ query.sql|safe }}</td>
</tr>
{% endfor %}
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html b/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
index cb3ca5e..64076e7 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql_explain.html
@@ -17,7 +17,7 @@
</thead>
<tbody>
{% for row in result %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
{% for column in row %}
<td>{{ column|escape }}</td>
{% endfor %}
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html b/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
index c058b2b..f53dcc0 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql_profile.html
@@ -17,7 +17,7 @@
</thead>
<tbody>
{% for row in result %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
{% for column in row %}
<td>{{ column|escape }}</td>
{% endfor %}
diff --git a/debug_toolbar/templates/debug_toolbar/panels/sql_select.html b/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
index c2ab7b6..1438050 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/sql_select.html
@@ -18,7 +18,7 @@
</thead>
<tbody>
{% for row in result %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
{% for column in row %}
<td>{{ column|escape }}</td>
{% endfor %}
diff --git a/debug_toolbar/templates/debug_toolbar/panels/timer.html b/debug_toolbar/templates/debug_toolbar/panels/timer.html
index 2d409b0..f593b44 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/timer.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/timer.html
@@ -13,7 +13,7 @@
</thead>
<tbody>
{% for key, value in rows %}
- <tr class="{% cycle 'odd' 'even' %}">
+ <tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
<td>{{ key|escape }}</td>
<td>{{ value|escape }}</td>
</tr>
diff --git a/debug_toolbar/templates/debug_toolbar/redirect.html b/debug_toolbar/templates/debug_toolbar/redirect.html
index cdc08b9..5611977 100644
--- a/debug_toolbar/templates/debug_toolbar/redirect.html
+++ b/debug_toolbar/templates/debug_toolbar/redirect.html
@@ -4,7 +4,7 @@
</head>
<body>
<h1>HttpResponseRedirect</h1>
-<p>Location: <a href="{{ redirect_to }}">{{ redirect_to }}</a></p>
+<p>Location: <a href="{{ redirect_to|urlencode }}">{{ redirect_to }}</a></p>
<p class="notice">
{% trans "The Django Debug Toolbar has intercepted a redirect to the above URL for
debug viewing purposes. You can click the above link to continue with the
diff --git a/debug_toolbar/toolbar/loader.py b/debug_toolbar/toolbar/loader.py
index b217665..c7f999e 100644
--- a/debug_toolbar/toolbar/loader.py
+++ b/debug_toolbar/toolbar/loader.py
@@ -18,9 +18,10 @@ class DebugToolbar(object):
'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel',
'debug_toolbar.panels.headers.HeaderDebugPanel',
'debug_toolbar.panels.request_vars.RequestVarsDebugPanel',
- 'debug_toolbar.panels.template.TemplateDebugPanel',
'debug_toolbar.panels.sql.SQLDebugPanel',
- 'debug_toolbar.panels.cache.CacheDebugPanel',
+ 'debug_toolbar.panels.template.TemplateDebugPanel',
+ #'debug_toolbar.panels.cache.CacheDebugPanel',
+ 'debug_toolbar.panels.signals.SignalDebugPanel',
'debug_toolbar.panels.logger.LoggingPanel',
)
self.load_panels()
diff --git a/debug_toolbar/urls.py b/debug_toolbar/urls.py
index 77d1a80..77491e3 100644
--- a/debug_toolbar/urls.py
+++ b/debug_toolbar/urls.py
@@ -7,10 +7,12 @@ this into the urlconf for the request.
from django.conf.urls.defaults import *
from django.conf import settings
+_PREFIX = '__debug__'
+
urlpatterns = patterns('',
- url(r'^__debug__/m/(.*)$', 'debug_toolbar.views.debug_media'),
- url(r'^__debug__/sql_select/$', 'debug_toolbar.views.sql_select', name='sql_select'),
- url(r'^__debug__/sql_explain/$', 'debug_toolbar.views.sql_explain', name='sql_explain'),
- url(r'^__debug__/sql_profile/$', 'debug_toolbar.views.sql_profile', name='sql_profile'),
- url(r'^__debug__/template_source/$', 'debug_toolbar.views.template_source', name='template_source'),
+ url(r'^%s/m/(.*)$' % _PREFIX, 'debug_toolbar.views.debug_media'),
+ url(r'^%s/sql_select/$' % _PREFIX, 'debug_toolbar.views.sql_select', name='sql_select'),
+ url(r'^%s/sql_explain/$' % _PREFIX, 'debug_toolbar.views.sql_explain', name='sql_explain'),
+ url(r'^%s/sql_profile/$' % _PREFIX, 'debug_toolbar.views.sql_profile', name='sql_profile'),
+ url(r'^%s/template_source/$' % _PREFIX, 'debug_toolbar.views.template_source', name='template_source'),
)
diff --git a/debug_toolbar/views.py b/debug_toolbar/views.py
index e3bb5b1..9123a00 100644
--- a/debug_toolbar/views.py
+++ b/debug_toolbar/views.py
@@ -8,16 +8,22 @@ import os
import django.views.static
from django.conf import settings
from django.db import connection
-from django.http import HttpResponse, HttpResponseBadRequest
+from django.http import HttpResponseBadRequest
from django.shortcuts import render_to_response
from django.utils import simplejson
from django.utils.hashcompat import sha_constructor
+class InvalidSQLError(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
def debug_media(request, path):
root = getattr(settings, 'DEBUG_TOOLBAR_MEDIA_ROOT', None)
if root is None:
parent = os.path.abspath(os.path.dirname(__file__))
- root = os.path.join(parent, 'media')
+ root = os.path.join(parent, 'media', 'debug_toolbar')
return django.views.static.serve(request, path, root)
def sql_select(request):
@@ -36,7 +42,7 @@ def sql_select(request):
hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest()
if hash != request.GET.get('hash', ''):
return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert
- if sql.lower().startswith('select'):
+ if sql.lower().strip().startswith('select'):
params = simplejson.loads(params)
cursor = connection.cursor()
cursor.execute(sql, params)
@@ -50,6 +56,7 @@ def sql_select(request):
'headers': headers,
}
return render_to_response('debug_toolbar/panels/sql_select.html', context)
+ raise InvalidSQLError("Only 'select' queries are allowed.")
def sql_explain(request):
"""
@@ -67,7 +74,7 @@ def sql_explain(request):
hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest()
if hash != request.GET.get('hash', ''):
return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert
- if sql.lower().startswith('select'):
+ if sql.lower().strip().startswith('select'):
params = simplejson.loads(params)
cursor = connection.cursor()
cursor.execute("EXPLAIN %s" % (sql,), params)
@@ -81,6 +88,7 @@ def sql_explain(request):
'headers': headers,
}
return render_to_response('debug_toolbar/panels/sql_explain.html', context)
+ raise InvalidSQLError("Only 'select' queries are allowed.")
def sql_profile(request):
"""
@@ -98,7 +106,7 @@ def sql_profile(request):
hash = sha_constructor(settings.SECRET_KEY + sql + params).hexdigest()
if hash != request.GET.get('hash', ''):
return HttpResponseBadRequest('Tamper alert') # SQL Tampering alert
- if sql.lower().startswith('select'):
+ if sql.lower().strip().startswith('select'):
params = simplejson.loads(params)
cursor = connection.cursor()
cursor.execute("SET PROFILING=1") # Enable profiling
@@ -116,6 +124,7 @@ def sql_profile(request):
'headers': headers,
}
return render_to_response('debug_toolbar/panels/sql_explain.html', context)
+ raise InvalidSQLError("Only 'select' queries are allowed.")
def template_source(request):
"""
diff --git a/setup.py b/setup.py
index 1d3f939..073e5e6 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@ setup(
author='Rob Hudson',
author_email='rob@cogit8.org',
url='http://rob.cogit8.org/blog/2008/Sep/19/introducing-django-debug-toolbar/',
- #download_url='http://github.com/robhudson/django-debug-toolbar/tree/master',
+ download_url='http://github.com/robhudson/django-debug-toolbar/downloads',
license='BSD',
packages=find_packages(exclude=['ez_setup']),
include_package_data=True,