Inspired by Cal Henderson's Keynote Presentation at Django Con 2008 I have set out to implement better debugging for Django's SQL queries. The goal is to tack on some helpful stack information as a comment at the end of every query. Once applied, when you have DEBUG set to True, queries show up like this example:

SELECT "django_content_type"."id", "django_content_type"."name", ...
FROM  "django_content_type"
WHERE  ("django_content_type"."model" = 'album' AND  ...
-- File ".../project/app/views.py", line 74, in fetch_contenttypes

Notice the last line which contains the comment. The snippet rolls back out of the Django internals to the last made call. At this point, which hopefully is someplace in your application, it appends the file, line number, and location to your query as an SQL comment. Here is the meat of the Python code:

if settings.DEBUG:
    import django
    from traceback import extract_stack
    from os.path import dirname
    stack = extract_stack()
    stack.reverse()
    dj_base = dirname(django.__file__)
    for frame in stack:
        if not frame[0].startswith(dj_base):
            sql += ' -- File "%s", line %d, in %s' % frame[:3]
            break

And here is the official patch im releasing against the trunk (but it should work on just about any recent release)

Index: django/db/models/sql/query.py
===================================================================
--- django/db/models/sql/query.py   (revision 11580)
+++ django/db/models/sql/query.py   (working copy)
@@ -8,7 +8,7 @@
 """

 from copy import deepcopy
-
+from django.conf import settings
 from django.utils.tree import Node
 from django.utils.datastructures import SortedDict
 from django.utils.encoding import force_unicode
@@ -2365,6 +2365,19 @@
                 return empty_iter()
             else:
                 return
+        
+        if settings.DEBUG:
+            import django
+            from traceback import extract_stack
+            from os.path import dirname
+            stack = extract_stack()
+            stack.reverse()
+            dj_base = dirname(django.__file__)
+            for frame in stack:
+                if not frame[0].startswith(dj_base):
+                    sql += ' -- File "%s", line %d, in %s' % frame[:3]
+                    break    
+
         cursor = self.connection.cursor()
         cursor.execute(sql, params)

This is not to be used in a production setting, which is why it only comments your queries when DEBUG is True, but it is a very handy tool to nail down exactly where your queries are coming from in your application. I will probably eventually file a ticket to this effect and see how it is received (dont hold ur breath, im super lazy ;-P )

4 Comments
Cracking feature. File the ticket!
This is awesome!
Um ... DEBUG can be set to True in production settings. We're actually pretty careful about letting that be the case (e.g. blanking out password information in the debug screen). Extracting the stack every single time like this would impose an unacceptable performance impact in those cases. I suspect a better approach here would be to extend the SQL reporting module in django-debug-toolbar to provide this information, perhaps via a callout hook so that the changes to core are minimal.
Finally the voice of reason ive been lookin for. I can understand having DEBUG set to True in some production settings, like setting up dev code on a live site and seeing if there are any issues. Ive done this on several occasions (though not for very long periods of time) and this kind of patch would hurt performance under any regular amount of load. This patch was basically just a proof of concept, and i was weary at hacking the core execute method with DEBUG or not (apparently execute is kind of an important function in webapps). A much better place for this would be in the debug-toolbar and Im thinkin it belongs in debug_toolbar.panels.sql.DatabaseStatTracker.execute, so i will try patching this soon and see if it takes. I am also open to any suggestions of other possible locations to stick this sucker.
Commenting is disabled for this entry.
If you feel there is still something worth mentioning about this entry please contact the author or the site admin.