django/django
URL routing
django/urls/ resolves an incoming request path to a view callable and supports the inverse — given a view name, produce the URL that maps to it. The implementation is a tree of resolvers and patterns, with named groups, path converters, and namespaces layered on top.
Purpose
Map URLs to views without coupling either side to a specific routing format. The framework supports two pattern styles — the modern path()/re_path() and the legacy url() (regex-only). Both compile to the same internal pattern tree.
Directory layout
django/urls/
├── __init__.py
├── base.py # resolve(), reverse(), translate_url(), set_script_prefix()
├── conf.py # path(), re_path(), include() — what users put in urls.py
├── converters.py # path converter classes (int, str, slug, uuid, path)
├── exceptions.py # NoReverseMatch, Resolver404
├── resolvers.py # URLPattern, URLResolver, ResolverMatch (the engine)
└── utils.py # get_callable, get_mod_func helpersKey abstractions
| Type | File | Role |
|---|---|---|
URLPattern |
resolvers.py |
A single (pattern, view, name) triple |
URLResolver |
resolvers.py |
A node holding a list of patterns/sub-resolvers + namespace info |
RoutePattern |
resolvers.py |
The path()-style pattern matcher |
RegexPattern |
resolvers.py |
The re_path()/url()-style pattern matcher |
LocalePrefixPattern |
resolvers.py |
Locale-prefixed pattern wrapper for i18n |
ResolverMatch |
resolvers.py |
The resolved (view, args, kwargs, url_name, app_names, namespaces) tuple |
path(), re_path(), include() |
conf.py |
Public constructors users call in urls.py |
IntConverter, UUIDConverter, SlugConverter, StringConverter, PathConverter |
converters.py |
Built-in path converters |
How it works
graph TD
Request["request.path_info<br/>e.g., '/articles/2025/12/'"]
RootConf["ROOT_URLCONF<br/>(settings)"]
RootResolver["URLResolver"]
Walk["walk children:<br/>URLPattern / sub-URLResolver"]
Match["ResolverMatch"]
View["view(request, *args, **kwargs)"]
Request --> RootResolver
RootConf --> RootResolver
RootResolver --> Walk
Walk -->|match| Match
Match --> ViewResolution
resolve(path) (in django/urls/base.py) walks the resolver tree:
- Start at the root
URLResolver— built fromsettings.ROOT_URLCONFand cached. - Try each pattern's
match(path)method. A match returns the consumed prefix and any captured args/kwargs. - If a sub-resolver matches a prefix, recurse with the remainder of the path.
- If a
URLPatternmatches the entire path, build aResolverMatchwith merged args/kwargs and return it. - If nothing matches, raise
Resolver404.
The resolver tree is cached after the first call. Reverse lookups consult the same tree but walk it in reverse.
Patterns
path() accepts a route string with <converter:name> placeholders. Internally it's parsed by RoutePattern into a regex — <int:year> becomes (?P<year>[0-9]+), <slug:slug> becomes (?P<slug>[-a-zA-Z0-9_]+), etc. The conversion is two-way: matched values run through to_python(); reverse calls run through to_url().
re_path() (and the legacy url()) take a raw regex. Capture groups become positional or named arguments. There's no path-converter pipeline — values come back as strings.
include() (in conf.py) splices another URLconf module's urlpatterns into the resolver tree. It also takes optional namespace and app_name arguments for namespace resolution.
Reverse lookup
reverse(viewname, args=..., kwargs=...) walks the same tree and emits a URL string. The tree is indexed by url_name, so reverse lookup is O(1) for a name plus O(depth) to assemble the path.
Namespaced names ('admin:index', 'myapp:detail') are resolved by splitting on : and traversing nested namespaces.
Path converters
Built-in converters in django/urls/converters.py:
| Converter | regex | to_python |
|---|---|---|
int |
[0-9]+ |
int(value) |
str |
[^/]+ |
str (the default) |
slug |
[-a-zA-Z0-9_]+ |
str |
uuid |
[0-9a-f]{8}-... |
uuid.UUID(value) |
path |
.+ |
str |
Custom converters register via register_converter(MyConverter, "myname").
set_script_prefix
SCRIPT_NAME (the WSGI prefix) is handled by a thread-local prefix in django/urls/base.py. django.setup() calls set_script_prefix(). reverse() prepends this prefix; resolve() expects request.path_info (which excludes the prefix).
Integration points
- Middleware chain (http) calls
resolve()after the middleware'sprocess_requestphase. - Class-based views (
django/views/generic/base.py) —View.as_view()returns a callable that the resolver matches on. - Namespaces — used by every contrib app and by user apps to avoid name collisions.
- i18n (
django/utils/translation/) —LocalePrefixPatternwraps the URLconf wheni18n_patterns()is used. - Templates (
{% url %}tag) and forms — both callreverse(). - Admin —
AdminSite.get_urls()builds a separate URLconf attached at the admin's mount point.
Entry points for modification
- New path converter: subclass with
regex,to_python,to_url. Register viaregister_converter(). - Custom resolver behaviour: subclass
URLResolverorURLPattern(rare). The pattern matchers inresolvers.pyare extension points. - URLconf reloading:
django/utils/autoreload.pycallsclear_url_caches()(django/urls/base.py) on every reload to invalidate the resolver tree.
Key source files
| File | Purpose |
|---|---|
django/urls/resolvers.py |
URLPattern, URLResolver, ResolverMatch, pattern classes (~1,000 lines) |
django/urls/base.py |
resolve, reverse, script prefix, URL caches |
django/urls/conf.py |
path(), re_path(), include() |
django/urls/converters.py |
Built-in path converters |
django/urls/exceptions.py |
NoReverseMatch, Resolver404 |
Where to read tests
tests/urlpatterns/—path()/re_path()matching.tests/urls/— historical legacy patterns.tests/test_client_regress/— end-to-end with reverse calls.tests/i18n/patterns/—i18n_patternsand locale prefixes.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.