Pdb can also print out all existing variables in global or local scope, by typing
locals() in (Pdb) prompt respectively.
Most basic Django debugging tool is pdb, a part of Python standard library.
Init view script
Let's examine a simple
from django.http import HttpResponse def index(request): foo = 1 bar = 0 bug = foo/bar return HttpResponse("%d goes here." % bug)
Console command to run server:
python manage.py runserver
It's obvious that Django would throw a
ZeroDivisionError when you try to load index page, but if we'll pretend that the bug is very deep in the code, it could get really nasty.
Setting a breakpoint
Fortunately, we can set a breakpoint to trace down that bug:
from django.http import HttpResponse # Pdb import import pdb def index(request): foo = 1 bar = 0 # This is our new breakpoint pdb.set_trace() bug = foo/bar return HttpResponse("%d goes here." % bug)
Console command to run server with pdb:
python -m pdb manage.py runserver
Now on page load breakpoint will trigger (Pdb) prompt in the shell, which will also hang your browser in pending state.
Debugging with pdb shell
It's time to debug that view by interacting with script via shell:
> ../views.py(12)index() -> bug = foo/bar # input 'foo/bar' expression to see division results: (Pdb) foo/bar *** ZeroDivisionError: division by zero # input variables names to check their values: (Pdb) foo 1 (Pdb) bar 0 # 'bar' is a source of the problem, so if we set it's value > 0... (Pdb) bar = 1 (Pdb) foo/bar 1.0 # exception gone, ask pdb to continue execution by typing 'c': (Pdb) c [03/Aug/2016 10:50:45] "GET / HTTP/1.1" 200 111
In the last line we see that our view returned an
OK response and executing as it should.
To stop pdb loop, just input
q in a shell.
First, you need to install django-debug-toolbar:
pip install django-debug-toolbar
Next, include it to project's installed apps, but be careful - it's always a good practice to use a different
settings.py file for such development-only apps and middlewares as debug toolbar:
# If environment is dev... DEBUG = True INSTALLED_APPS += [ 'debug_toolbar', ] MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
Debug toolbar also relies on static files, so appropriate app should be included as well:
INSTALLED_APPS = [ # ... 'django.contrib.staticfiles', # ... ] STATIC_URL = '/static/' # If environment is dev... DEBUG = True INSTALLED_APPS += [ 'debug_toolbar', ]
In some cases, it's also required to set
INTERNAL_IPS = ('127.0.0.1', )
urls.py, as official documentation suggests, the next snippet should enable debug toolbar routing:
if settings.DEBUG and 'debug_toolbar' in settings.INSTALLED_APPS: import debug_toolbar urlpatterns += [ url(r'^__debug__/', include(debug_toolbar.urls)), ]
Collect toolbar's static after installation:
python manage.py collectstatic
That's it, debug toolbar will appear on you project's pages, providing various useful information about execution time, SQL, static files, signals, etc.
django-debug-toolbar requires a Content-type of
<body> tags to render properly.
In case if you sure you've configured everything right, but debug toolbar is still not rendered: use this "nuclear" solution to try to figure it out.
While developing, inserting the following line to your code:
assert False, value
will cause django to raise an
AssertionError with the value supplied as an error message when this line is executed.
If this occurs in a view, or in any code called from a view, and
DEBUG=True is set, a full and detailed stacktrace with a lot of debugging information will be displayed in the browser.
Don't forget to remove the line when you are done!
Debugging takes time and effort.
Instead of chasing bugs with a debugger, consider spending more time on making your code better by:
assertions to your code in important places: Reduce ambiguity, catch problems as they are created.
Bonus: Write doctests for combining documentation and testing!