Originally based on: http://djangosnippets.org/snippets/1872/
The way the original snippet formatted sql didn't work for mysql properly so I taught it to use the sqlparse python module. Now it looks like this when settings.DEBUG=True:
SQL executed:
SELECT "django_session"."session_key",
"django_session"."session_data",
"django_session"."expire_date"
FROM "django_session"
WHERE ("django_session"."session_key" = d326108d313a2e5c5fb417364b005ab9
AND "django_session"."expire_date" > 2011-04-08 14:54:13.969881)
took 0.001 seconds
SELECT "auth_user"."id",
"auth_user"."username",
"auth_user"."first_name",
"auth_user"."last_name",
"auth_user"."email",
"auth_user"."password",
"auth_user"."is_staff",
"auth_user"."is_active",
"auth_user"."is_superuser",
"auth_user"."last_login",
"auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" = 2
took 0.000 seconds
Additionally, this middlware is enabled conditionally based upon the url query string "debug". You can enable it for a single request by appending: ?debug=true to the url.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | # Originally based on: http://djangosnippets.org/snippets/1872/
# Requires sqlparse: http://pypi.python.org/pypi/sqlparse
import time
from django.test.signals import template_rendered
from django.conf import settings
from django.db import connection
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
TEMPLATE = """
<div id="debug" style="clear:both;">
<a href="#debugbox"
onclick="this.style.display = 'none';
document.getElementById('debugbox').style.display = 'block';
return false;"
style="font-size: small; color: red; text-decoration: none; display: block; margin: 12px;"
>+</a>
<div style="display: none;clear: both; border: 1px solid red; padding: 12px; margin: 12px; overflow: scroll; white-space: wrap;" id="debugbox">
<p>Server-time taken: {{ server_time|floatformat:"5" }} seconds</p>
<p>View: <strong>{{view}}</strong></p>
<p>Templates used:</p>
{% if templates %}
<ol>
{% for template in templates %}
<li><strong>{{ template.0 }}</strong> loaded from <samp>{{ template.1 }}</samp></li>
{% endfor %}
</ol>
{% else %}
None
{% endif %}
<p>Template path:</p>
{% if template_dirs %}
<ol>
{% for template in template_dirs %}
<li>{{ template }}</li>
{% endfor %}
</ol>
{% else %}
<ul><li>None</li></ul>
{% endif %}
<p>SQL executed:</p>
{% if sql %}
<pre style="margin-left: 2em;">{% for query in sql %}{{ query.sql }}
<strong>took {{ query.time|floatformat:"3" }} seconds</p>{{ query.count }}</strong>
{% endfor %}</pre>
<p>Total SQL time: {{ sql_total }} in {{num_queries}} queries</p>
{% else %}
{% if not debug %}
<ol><li>Showing full queries is disabled when settings.DEBUG = False.</li></ol>
{% else %}
None
{% endif %}
{% endif %}
</div>
</div>
</body>
"""
# Monkeypatch instrumented test renderer from django.test.utils - we could use
# django.test.utils.setup_test_environment for this but that would also set up
# e-mail interception, which we don't want
from django.test.utils import instrumented_test_render
from django.template import Template, Context
if Template.render != instrumented_test_render:
Template.original_render = Template.render
Template.render = instrumented_test_render
# MONSTER monkey-patch
old_template_init = Template.__init__
def new_template_init(self, template_string, origin=None, name='<Unknown Template>'):
old_template_init(self, template_string, origin, name)
self.origin = origin
Template.__init__ = new_template_init
class DebugFooter:
def process_request(self, request):
self.time_started = time.time()
self.templates_used = []
self.contexts_used = []
self.sql_offset_start = len(connection.queries)
template_rendered.connect(self._storeRenderedTemplates)
def process_response(self, request, response):
# Don't bother if the url doesn't have the "debug" query string
# Added by Jeff Schroeder for dynamically enabling/disabling this
if not request.GET.has_key("debug"):
return response
# Only include debug info for text/html pages not accessed via Ajax
if 'text/html' not in response['Content-Type']:
return response
if request.is_ajax():
return response
if response.status_code != 200:
return response
templates = []
for t in self.templates_used:
if t.origin and t.origin.name:
templates.append( (t.name, t.origin.name) )
else:
templates.append( (t.name, "no origin") )
sql_queries = connection.queries[self.sql_offset_start:]
# Reformat sql queries a bit
sql_total = 0.0
sql_counts = {}
for query in sql_queries:
raw_sql = query['sql']
query['sql'] = reformat_sql(query['sql'])
sql_total += float(query['time'])
count = sql_counts.get(raw_sql,0) + 1
sql_counts[raw_sql] = count
if count > 1:
query['count'] = mark_safe('<p>duplicate query count=%s</p>' % count)
else:
query['count'] = ''
from django.core.urlresolvers import resolve
view_func = resolve(request.META['PATH_INFO'])[0]
view = '%s.%s' % (view_func.__module__, view_func.__name__)
vf = view_func
breaker = 10
while not hasattr(vf,'func_code'):
if hasattr(vf,'view_func'):
vf = vf.view_func
else:
break # somethings wrong about the assumptions of the decorator
breaker = breaker - 1
if breaker < 0:
break
if hasattr(vf,'func_code'):
co = vf.func_code
filename = co.co_filename
lineno = co.co_firstlineno
view = '- '.join([view, ':'.join([co.co_filename, str(co.co_firstlineno)])])
debug_content = Template(TEMPLATE).render(Context({
'debug': settings.DEBUG,
'server_time': time.time() - self.time_started,
'templates': templates,
'sql': sql_queries,
'sql_total': sql_total,
'num_queries' : len(sql_queries),
'template_dirs': settings.TEMPLATE_DIRS,
'view': view
}))
content = response.content
response.content = force_unicode(content).replace('</body>', debug_content)
return response
def _storeRenderedTemplates(self, **kwargs):
template = kwargs.get('template')
if(template):
self.templates_used.append(template)
context = kwargs.get('context')
if(context):
self.contexts_used.append(context)
def reformat_sql(sql):
if sql:
import sqlparse
sql = sqlparse.format(sql, reindent=True, keyword_case='upper')
return sql
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 9 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 9 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 4 months ago
- Help text hyperlinks by sa2812 1 year, 5 months ago
Comments
Have you considered using DDT (Django Debug Toolbar) ??
#
Please login first before commenting.