Skip to content

Django Debug Tools

Bugs happen in every project - even for experienced developers. Debugging is not a sign that you’re doing something wrong. It’s just a normal part of building things. Good developers are not the ones who never get bugs. They’re the ones who can find what went wrong quickly and fix it properly.

Follow these steps every time something breaks. Don’t skip steps - it saves time in the long run:

  1. Make the bug happen again so you know exactly what triggers it.
  2. Read the full error message from top to bottom.
  3. Find the exact file and line number where the error happened.
  4. Understand why it broke, not just where.
  5. Make a small, focused fix.
  6. Test the same thing again to confirm it’s fixed.

The most important rule: fix the actual cause, not just the error message. If you just hide the error without understanding it, it will come back.

You don’t need just one tool - different tools answer different questions. Use them together:

  • Django traceback - the error page in your browser or terminal that shows what went wrong.
  • Temporary print statements - quick and dirty way to check values in your code locally.
  • Breakpoints in VS Code - pause your running code and look inside it like a microscope.
  • Django shell - a Python terminal connected to your project, great for testing database queries.
  • Application logs - a record of what your app did during each request, useful for finding issues in production.

When Django shows you an error, don’t panic. Read it from the bottom up.

The bottom lines tell you:

  • What type of error it is (e.g. AttributeError, KeyError, DoesNotExist)
  • A message explaining what went wrong
  • The exact line of code that caused it

Then read upward to understand the chain of code that led to that point.

Don’t start changing code before you understand the full picture. Guessing and changing random things makes debugging take much longer.

The Django shell is a Python terminal that’s already connected to your project and database. It’s great when you want to test a query or check your data without having to click through pages in the browser.

Open the shell:

Terminal window
uv run python manage.py shell

Example - check your database data:

from core.models import Product
Product.objects.count()
Product.objects.first()

Use the shell for:

  • Checking what’s actually in the database
  • Testing ORM queries before putting them in your views
  • Trying out small bits of logic quickly

print() is fine for quick checks on your own computer, but once you’re working with a team or on a real server, logs are much better. They stay recorded even after the request is done, and you can filter them by how serious the message is.

Here’s a simple logging setup in settings.py that sends logs to the terminal:

LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "INFO",
},
"loggers": {
"django.request": {
"handlers": ["console"],
"level": "ERROR",
"propagate": False,
},
},
}

Things to keep in mind when logging in production:

  • Never log passwords, tokens, or private user data. Logs can be read by many people.
  • Use the right level for each message - DEBUG, INFO, WARNING, or ERROR - so it’s easy to filter later.
  • If your project gets a lot of traffic, add request IDs to logs so you can trace one user’s journey through many log lines.

Django Debug Toolbar is a panel that appears on the side of your web pages while you’re developing. It shows you useful information about what Django did to build that page.

You can use it to see:

  • Every SQL query that ran for that page, and how long each one took
  • Which templates were used and how long rendering took
  • Request headers and current Django settings
  • Cache and middleware activity

This is really useful for catching slow database queries before they become a problem on a live site.

Terminal window
uv add django-debug-toolbar
INSTALLED_APPS = [
# other apps...
]
if ENVIRONMENT != PRODUCTION:
INSTALLED_APPS += [
# ...
"debug_toolbar",
]
MIDDLEWARE = [
# other middleware...
]
if ENVIRONMENT != PRODUCTION:
MIDDLEWARE += [
# ...
"debug_toolbar.middleware.DebugToolbarMiddleware",
]
INTERNAL_IPS = [
"127.0.0.1",
]

The if ENVIRONMENT != PRODUCTION checks make sure the toolbar only runs on your local machine, never on the real server.

from django.conf import settings
from django.urls import include, path
urlpatterns = [
# your URLs...
]
if settings.ENVIRONMENT != settings.PRODUCTION:
urlpatterns += [
path("__debug__/", include("debug_toolbar.urls")),
]
  • Only use the Debug Toolbar in development - never on a live site.
  • Always keep it behind settings.DEBUG or environment checks.
  • Never expose the __debug__/ URL in production - it leaks internal details about your app.

A good way to describe this tool in interviews:

“I use Django Debug Toolbar to find slow database queries and catch N+1 problems before the site goes live.”

Sometimes print() and logs aren’t enough. When a bug is really tricky, you can use VS Code’s debugger to pause your running Django server at any line of code and look at exactly what’s happening at that moment - variable values, what function called what, etc.

  • VS Code Python extension installed.
  • Your Django project folder open at the root (the folder where manage.py lives).

This file tells VS Code how to start Django in debug mode:

{
"version": "0.2.0",
"configurations": [
{
"name": "Django: Runserver",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/manage.py",
"args": ["runserver"],
"django": true,
"justMyCode": true,
"console": "integratedTerminal",
"env": {
"DJANGO_SETTINGS_MODULE": "myproject.settings"
}
}
]
}

Replace myproject.settings with your actual project name and settings file path.

{
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.analysis.typeCheckingMode": "basic"
}
  1. Click on the line number in a view, serializer, or any function where you want to pause - this sets a breakpoint (a red dot appears).
  2. Go to the Run and Debug panel in VS Code and start Django: Runserver.
  3. Open your browser and trigger the page or action that calls that code.
  4. VS Code will pause the code right at your breakpoint.
  5. You can now look at the current value of every variable, step through the code one line at a time, and understand exactly what’s happening.
  • Make sure you started Django using the Django debug config, not a regular terminal command.
  • Check that the request is actually reaching the file and function where you put the breakpoint.
  • Restart the debug session after making any code or config changes.