Path Converters
The cookbook has hundreds of recipes. Writing one pattern per recipe would be absurd. Instead, one pattern says "a recipe's slug goes here", captures it, and hands it to the view. Converters are how you say what may go in that slot.
The rule
<type:name>— the type filters the text, the name becomes an argument.
urlpatterns = [
path("<slug:slug>/", views.recipe_detail),
path("page/<int:number>/", views.recipe_page),
]
def recipe_page(request, number):
... # number is already an int, e.g. 3The name must match a parameter of the view. The type does two jobs: it decides what text matches, and it converts the text before your view sees it.
The built-in converters:
| Converter | Matches | View receives |
|---|---|---|
str (the default) |
any non-empty text without / |
str |
int |
zero or a positive whole number | int |
slug |
letters, numbers, hyphens, underscores | str |
uuid |
a UUID such as 075194d3-6885-417e-a8a8-6c931e272f00 |
uuid.UUID |
path |
any non-empty text, including / |
str |
<name> with no type means <str:name>.
If the text does not fit the converter, the pattern simply does not match. Django moves on to the next pattern, and if nothing else fits, the answer is 404. Your view never sees bad input like three where a number belongs.
You can register your own converter too, a small class with a regex attribute and to_python and to_url methods, when the built-ins do not fit, such as a four-digit year.
The shortcut
Ask "what does a valid value look like?" and pick the narrowest converter that fits it. Numbers → int. URL-friendly names → slug. Needs slashes → path. The narrower the converter, the more junk is turned away before your code runs.
Match the fixed part
page/matches in both cases.
The trap is writing <str:page> and then int(page) inside the view: extra code, and a crash on bad input instead of a clean 404.
Drills
Answer fast — trust the rule.
Which converter would capture 2025/menus/summer.pdf as one value?
For path("page/<int:number>/", views.recipe_page), what type is number inside the view?
What does <title> with no converter type mean?
Which value does the slug converter reject?
What happens at /recipes/page/-1/ if the only matching candidate is page/<int:number>/?
Remember
<type:name>: the type filters and converts, the name becomes the argument.- Pick the narrowest converter that fits a valid value.
- Trap: capturing
strand converting by hand in the view.
