skip to content

In Django's path() routes, what do the built-in str, int, slug, uuid and path converters match, and what does the view receive?

level: juniorimportance: must knowfreq 62%

answer

  1. five names registered by default
  2. one segment versus many segments
  3. only two change the Python type
  4. a bare <name> has a default
  5. lowercase dashed form only

basics

~20 s

str (the default) matches one non-empty segment without a slash; int matches digits and passes an int; slug matches ASCII letters, digits, hyphens and underscores; uuid matches a lowercase dashed UUID and passes uuid.UUID; path matches anything non-empty, slashes included.

solid answer

~40 s

Django registers five converters in `django.urls.converters`. `str` matches `[^/]+`, one non-empty segment, and is what a bare `<name>` means. `int` matches `[0-9]+` and calls `int()`, so the view gets an integer; a minus sign never matches. `slug` matches `[-a-zA-Z0-9_]+` and still passes a string, so Unicode slugs do not fit it. `uuid` accepts only the lowercase, dashed form and passes a `uuid.UUID`. `path` matches `.+`, slashes included, so it belongs at the end of a route. When text does not fit a converter's regex, that pattern simply does not match and Django tries the next one; if nothing matches, the request gets a 404 and the view never runs.

code

python · 13 lines
python
import uuid

from django.http import HttpRequest, HttpResponse


# path('events/<slug:slug>/sessions/<int:number>/', session_detail)
def session_detail(request: HttpRequest, slug: str, number: int) -> HttpResponse:
    return HttpResponse(f'{slug} session {number}')


# path('tickets/<uuid:code>/', ticket_detail)
def ticket_detail(request: HttpRequest, code: uuid.UUID) -> HttpResponse:
    return HttpResponse(f'ticket {code.hex}')

go deeper

for a junior

Recall the five converter names, that str is the default for a bare <name>, and that int and uuid hand the view converted values while the others pass strings.

for a middle

Explain that each converter is a regex plus to_python(), that a regex mismatch makes the pattern decline rather than error, and the leading-zero and uppercase-UUID edges.

for a senior

Choose converters for canonical URLs: uuid for public ticket codes, int for keys, and be clear that converters validate shape only, never existence or access.

for a principal

Treat URL shape as a public contract: the identifier format behind each converter decides which links stay valid, so settle slugs versus UUIDs before URLs ship.

## What a path converter is In Django, a **URLconf** is a Python module with a `urlpatterns` list. Each entry made with `django.urls.path()` takes a **route** string such as `'events/<slug:slug>/'`. Text outside the angle brackets is matched literally; each `<converter:name>` placeholder captures one value and passes it to the view as the keyword argument `name`. If you omit the converter and write `<name>`, Django uses `str`. A **path converter** decides two things for its placeholder: - which text it accepts, through a `regex` attribute; - what Python value the view receives, through its `to_python()` method. Django compiles one regular expression per route when `path()` is called, escaping the literal text and splicing in each converter's regex. At request time the captured strings go through `to_python()` before the view is called. ## The five built-in converters Django 6.1 registers five converters by default: | Converter | Regex | Example match | View receives | |---|---|---|---| | `str` | `[^/]+` | `launch-party` | `str` | | `int` | `[0-9]+` | `42` | `int` | | `slug` | `[-a-zA-Z0-9_]+` | `jazz-night_2026` | `str` | | `uuid` | lowercase, dashed 8-4-4-4-12 hex | `075194d3-6885-417e-a8a8-6c931e272f00` | `uuid.UUID` | | `path` | `.+` | `press/2026/poster.pdf` | `str` | Only `int` and `uuid` change the Python type. `slug` and `path` hand the view a plain string; they differ from `str` only in which text they accept. ## A ticketing URLconf ```python from django.urls import path from . import views urlpatterns = [ path('events/', views.event_list, name='event-list'), path('events/<slug:slug>/', views.event_detail, name='event-detail'), path('events/<slug:slug>/sessions/<int:number>/', views.session_detail, name='session-detail'), path('tickets/<uuid:code>/', views.ticket_detail, name='ticket-detail'), path('press-kit/<path:file_path>', views.press_kit_file, name='press-kit-file'), ] ``` A request for `/events/jazz-night/sessions/2/` calls `session_detail(request, slug='jazz-night', number=2)`, with `number` already an `int`. A request for `/tickets/075194d3-6885-417e-a8a8-6c931e272f00/` calls `ticket_detail(request, code=UUID('075194d3-...'))`, so the view can filter a `UUIDField` with `code` directly. ## How a route becomes a regular expression When `path('events/<slug:slug>/', ...)` runs, Django builds the expression `^events/(?P<slug>[-a-zA-Z0-9_]+)/` and, because this entry calls a view rather than including another URLconf, appends an end-of-string anchor. Two consequences are worth saying out loud in an interview: - **Literal text is escaped.** A dot or a plus sign in a `path()` route means that character, never a regex operator. - **Conversion runs both ways.** Each converter also has a `to_url()` method, used when Django builds a URL from a route name: `int` and `uuid` turn their values back into text with `str()`, and the string converters return the value unchanged. Because the regexes are fixed per converter, two routes that differ only in converter type, such as `events/<int:pk>/` and `events/<slug:slug>/`, can coexist: a numeric segment fits both, so list order decides which one answers it. ## Edge cases interviewers probe - **`<slug>` is not the slug converter.** The word inside the brackets is the argument name; the converter is what comes before the colon. `<slug>` means `str`, which also accepts dots, spaces and non-ASCII characters. - **`int` accepts only non-negative digits.** `-5` does not match. Leading zeros do: `/sessions/007/` passes `7`, so two URLs reach one page, while reversing the route writes `7`. - **`uuid` is strict.** Uppercase letters, missing dashes or braces do not match. That keeps one canonical URL per ticket, but a pasted uppercase code gets a 404. - **`slug` is ASCII-only.** A value from `SlugField(allow_unicode=True)`, such as an event name in Cyrillic, will not match `<slug:...>`; use `str` or a custom converter. - **`path` is greedy.** It swallows slashes, so it belongs at the end of a route and below narrower routes that share its prefix. - **None of them touch the database.** `<int:pk>` proves the text is digits, not that an event with that key exists; the view still looks the row up and returns a 404 for a miss. ## What happens when the text does not fit 1. Django tries the entries of `urlpatterns` in order. 2. If a converter's regex rejects the segment, that pattern does not match. No error is raised; the next pattern is tried. 3. If no pattern matches, resolution fails and the request gets Django's 404 response. The view is never called. This is why converters double as cheap input validation: `/tickets/not-a-uuid/` never reaches `ticket_detail`, so the view can trust the type of `code`. ## Choosing a converter - `int` for integer primary keys and ordinal numbers. - `slug` for human-readable identifiers stored in a `SlugField`. - `uuid` for public, hard-to-guess identifiers such as ticket codes. - `path` only when the value genuinely contains slashes, like a file path. - `str` for free-form single segments, and a custom converter when none of these fits.

  • What does Django's int converter do with /events/jazz-night/sessions/007/?
    It matches, because `[0-9]+` accepts leading zeros, and `int('007')` passes `7` to the view. Reversing the same route writes `7`, so `/sessions/007/` and `/sessions/7/` serve one page. If canonical URLs matter, redirect the padded form in the view or use a custom converter whose regex rejects leading zeros.
  • Why should a Django path converter usually sit at the end of a route?
    Its regex is `.+`, which crosses slashes, so it absorbs every remaining segment. Placed mid-route, the literal text after it becomes ambiguous; placed in an early entry, it can capture URLs meant for narrower routes listed after it. Put `<path:...>` last in the route and its route near the bottom of the list.
  • Does <int:pk> in a Django route guarantee the object exists?
    No. Converters only check and convert text; they run no query. The view still fetches the row, typically with `get_object_or_404()`, and returns a 404 when it is missing. The converter's value is that the view receives an `int` and never sees non-numeric input.

saying these in an interview costs you the question

  • Writing <slug> in a route makes Django apply the slug converter.
  • Django's int converter also matches negative numbers such as -5.
  • The uuid converter accepts uppercase letters and UUIDs without dashes.
  • The slug and path converters hand the view special objects rather than strings.
  • A converter confirms that a matching database row exists before the view runs.