URL Dispatch: Django's Own Mechanism for Arbitrary-Depth Routing
Website Rebuild with Django
Chapter 3 · URL Dispatch: Django's Own Mechanism for Arbitrary-Depth Routing
Website Rebuild with Next.js solved arbitrary-depth routing with a special filename: a folder literally named [...slug], whose presence alone tells Next.js "match anything here, and hand me the segments as an array." Django has no filename convention that does anything at all — every route is a line of ordinary Python, read top to bottom, matched in the exact order it's declared. Both frameworks reach the same end result; the actual mechanism underneath is genuinely different, and that difference is this chapter's whole subject.
Path Converters: What Actually Makes a Catch-All Possible
Django's path() function matches URL segments using named converters — str, int, slug, uuid. Every one of those stops at the first / it encounters. Only one converter doesn't: path, which matches literally anything, forward slashes included — the single piece of syntax this whole chapter is built around.
<path:full_path> means "match anything, including slashes, and pass it to the view as a keyword argument named full_path" — the direct equivalent of Next.js's own [...slug] array param, just delivered as a single string instead of an array of segments.
urlpatterns is an ordinary Python list, read and matched top to bottom, that you write and can see in full in one file. Neither approach is objectively better; they're two genuinely different philosophies (convention-over-configuration vs. explicit-is-better-than-implicit) that this whole course keeps surfacing, starting with Chapter 1's own project/app split.
The View: One Lookup, Not a Walk
This is exactly the payoff Chapter 2's own full_path field was built for: full_path arrives from the URL already in the identical shape it was stored in, so resolving any URL — no matter how deep — is one indexed database lookup, never a walk back up through parent.
Three Real Edge Cases
urlpatterns in declaration order and stops at the first match. If path('<path:full_path>/', ...) were listed before path('admin/', ...), a request for /admin/ would never reach the real admin route at all — full_path would greedily match "admin" first, and Django would call page_detail looking for a Page that was never meant to exist. The catch-all pattern has to be the very last entry in the list, always.
<path:full_path> requires at least one real character — it doesn't match an empty string, so the bare root URL / would 404 with only the catch-all pattern in place. path('', views.homepage, name='homepage') exists specifically to handle that one case the catch-all structurally can't.
/programming/python/ — but Chapter 2's save() method built full_path with no trailing slash ("programming/python"). Querying with the raw, unstripped full_path parameter would never match a single real row, for every single page, silently. full_path.rstrip('/') exists purely to close that exact gap before the query ever runs.
Django vs. Next.js: The Same Job, Two Mechanisms
| Next.js | Django | |
|---|---|---|
| How the catch-all is declared | A folder named [...slug] — a filename convention | A path() call using the path converter — an explicit line of code |
| What the handler receives | An array of individual URL segments | A single string, the full remaining path |
| Where routing logic lives | Discovered from the folder structure on disk | Declared explicitly in urlpatterns, read top to bottom |
Hands-On Exercises
Explain why Next.js's [...slug] file-based catch-all and Django's path('<path:full_path>/', ...) achieve the identical end result through genuinely different mechanisms. Name the actual mechanism each framework relies on.
Explain why the catch-all pattern must be listed last in urlpatterns, using a concrete example of what would actually break if it were listed before the admin/ route instead.
Explain why full_path.rstrip('/') is necessary inside page_detail, referencing exactly how full_path was built back in Chapter 2.
Chapter 3 Quick Reference
- Path converters —
str/int/slug/uuidall stop at a/; onlypathmatches through it <path:full_path>— Django's own catch-all syntax; delivers one string, unlike Next.js's array of segments- Explicit vs. implicit routing — Django's
urlpatternsis ordinary Python code; Next.js's routing table is the folder structure itself - Pattern order matters — the catch-all must be the last entry, or it swallows requests meant for earlier routes
- The homepage needs its own explicit
path('', ...)— the catch-all can't match an empty path full_path.rstrip('/')— reconciles Django's own trailing-slash convention against Chapter 2's own no-trailing-slashfull_pathstorage- Next chapter: Views & Templates: Django's MVT Model