Django: fix a view using pdb with breakpoint()

Python’s breakpoint() function opens its debugger, pdb, which pauses the program and allows you to inspect and modify things. Let’s look at an example of using it within a Django view, from a sample project included in Boost Your Django DX.
Here’s what the project looks like:

This page, “Party Central”, lists animals with their pizza preferences and whether they’re hungry. Underneath the table are two filter buttons, “Hungry” and “Satiated”, which allow you to select only animals with those hunger levels.
Unfortunately, the filter buttons are broken. Click “Hungry” to load http://localhost:8000/?hungry=1 and we see the same list of animals:

The hungry URL parameter is there, and the button is highlighted, but the data isn’t filtered. Let’s use pdb to figure out why.
We can run pdb with the breakpoint() function, a Python built-in that opens the configured debugger (which is pdb by default). Let’s add it to the view function, before it renders the template.
Here’s how the views.py file looks:
from django.shortcuts import render
from example.models import Animal
def index(request):
animals = Animal.objects.order_by("name")
hungry = request.GET.get("hunger")
if hungry is not None:
animals = animals.filter(is_hungry=hungry)
return render(
request,
"index.html",
{"animals": animals},
)
Modify it to call breakpoint() after the filtering attempt like so:
@@ -10,6 +10,8 @@ def index(request):
if hungry is not None:
animals = animals.filter(is_hungry=hungry)
+ breakpoint()
+
return render(
request,
"index.html",
After saving the file, runserver detects the change and reload. Then, after refreshing the page in the browser (http://localhost:8000/?hungry=1), and we see it never finishes loading. Instead, the server pauses with pdb open:
$ ./manage.py runserver
...
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
> /.../example/views.py(15)index()
-> return render(
(Pdb)
This is pdb’s prompt, a bit like the Python shell. We can use pdb commands to manipulate the running program.
First, let’s inspect the query parameters in request.GET:
(Pdb) request.GET
<QueryDict: {'hungry': ['1']}>
(Pdb)
Okay, the mapping contains a hungry parameter with the value '1', which matches what we see in the URL after clicking the “Hungry” filter.
Double-check the variable:
(Pdb) hungry
(Pdb)
Huh, no output, which generally means it’s None. We can double-check with the pp command, which pretty-prints values (using Python’s pprint module):
(Pdb) pp hungry
None
(Pdb)
Hmm, that’s odd. There’s definitely an issue with how the hungry variable is set.
Let’s try rerunning the expression from line 12 manually and compare that with request.GET:
(Pdb) pp request.GET.get("hunger")
None
(Pdb) request.GET
<QueryDict: {'hungry': ['1']}>
(Pdb)
Did you spot the issue yet? It’s a classic typo: hunger should be hungry.
We can check the correct key works:
(Pdb) pp request.GET.get("hungry")
'1'
(Pdb)
Yes, indeed. Time to correct the view and drop the breakpoint() call:
@@ -6,12 +6,10 @@
def index(request):
animals = Animal.objects.order_by("name")
- hungry = request.GET.get("hunger")
+ hungry = request.GET.get("hungry")
if hungry is not None:
animals = animals.filter(is_hungry=hungry)
- breakpoint()
-
return render(
request,
"index.html",
runserver will reload, automatically closing the pdb session:
$ ./manage.py runserver
...
(Pdb) /.../example/views.py changed, reloading.
Watching for file changes with StatReloader
...
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
And now the filter buttons work as expected:

Great, now we can run our pizza party with confidence.
Whilst this bug was a not-particularly-complicated typo, it would have been harder to spot without pdb. There was no traceback to look at, but we knew the issue was in the view. Compared to print() debugging, pdb allowed us to inspect the expressions we wanted without modifying the code, restarting the server, and reloading the page for each check.
Fin
For more on using pdb with Django, see the Debuggers chapter in Boost Your Django DX.
Take a break, point,
—Adam
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
Tags: django