Debugging a Django Application
There are numerous tools in the world designed to make debugging a Django
application much easier. Whether a template is taking too long to render, or an
API endpoint is crashing on certain input, there are better ways to debug than
inserting print
statements.
Django Debug Toolbar
The Django Debug Toolbar is a very useful tool that allows for viewing lots of information about how every page was rendered, including debug error pages. It adds a sidebar to rendered HTML requests that includes things like:
Django, Python, and toolbar versions
SQL queries needed to render the page, and their execution time
Timing information
Contents of settings
Page and WSGI headers
View information, including session data, POST data, view function name, view kwargs, etc.
Static and template files
Signals called during view
Logging
To install the toolbar, install it with pip
:
(venv) $ pip install django-debug-toolbar
and then add it to the project’s INSTALLED_APPS
:
# settings.py
INSTALLED_APPS = (
'my_project',
...
'debug_toolbar'
)
Run the app and it’s ready to go! Whenever DEBUG is set to True
, any
connection matching Django’s INTERNAL_IPS
will have the toolbar. For more
information on how to install it, see
their installation docs.
Note
For API calls that error out, Django Debug Toolbar can be used, since it shows up on debug error pages. However, you’ll need to use something like Django PDB to debug pages that don’t throw errors.
Django PDB
Python’s Debugger is useful for getting information from running processes,
including Django’s built-in log of SQL queries ran. Unlike the Django Debug
Toolbar above, PDB can be used for any endpoint, including API endpoints, making
it a much more useful utility (though much harder to use, since it requires
knowledge of Python’s debugger). Django PDB is a tool that can automatically
activate pdb
for any endpoint.
To set up django-pdb
, first install it with pip
:
(venv) $ pip install django-pdb
Then add it to the end of the application’s INSTALLED_APPS
:
# settings.py
INSTALLED_APPS = (
'my_project',
...
'django_pdb'
)
Add it to the end of the application’s MIDDLEWARE_CLASSES
:
# settings.py
MIDDLEWARE_CLASSES = (
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
...
'django_pdb.middleware.PdbMiddleware',
)
Now, run the development server as normal:
(venv) $ python manage.py runserver
To drop into pdb
for a particular request, add a pdb
parameter to the
request:
$ curl http://localhost:8000/v1/objects/1?pdb
A pdb
prompt should appear in the terminal where manage.py
is running.
$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
October 09, 2015 - 20:56:08
Django version 1.7.6, using settings 'project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
()
GET /v1/objects/1?pdb
function "myview" in app/views.py:8
args: ()
kwargs: {'id': u'1'}
()
> /home/user/projects/project/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py(66)make_view_atomic()
-> non_atomic_requests = getattr(view, '_non_atomic_requests', set())
(Pdb)
Normal pdb
commands can be used, including n(ext)
to skip to the next
line of the current function, s(tep)
to step to the next line, or into a
called function, and c(ontinue)
to jump to the next breakpoint.
To view SQL queries run in a certain view, for instance, clear the previous queries at the beginning of the view, step through the view until the return, and print Django’s queries list:
(Pdb) from django.db import reset_queries
(Pdb) n
...
-> def song(request, id=None):
(Pdb) n
..
-> return HttpResponse(
(Pdb) from django.db import connection
(Pdb) connection.queries
[{u'time': u'0.004', u'sql': u'QUERY = u\'SELECT "words_song"."id", "words_song"."name", "words_song"."video", "words_song"."slug" FROM "words_song" WHERE "words_song"."id" = %s LIMIT 21\' - PARAMS = (1,)'}]
(Pdb)
For more information on how to use pdb
, see the official debugger
documentation.