Course outline

Django / Request and data foundations / Lesson 2

URLs, converters, and route names

Map paths to views with explicit converters and stable names while separating routing from resource authorization.

About 4 min readContent reviewed
On this page

Lesson goals

  • A URLconf describes dispatch
  • Resolve a path in an isolated URL module
  • Review path changes as interface changes

A URLconf describes dispatch

A URL configuration maps incoming paths to view callables. Django examines patterns in order and dispatches the matching view with captured arguments. The query string is not part of the path pattern; a view reads query parameters separately. Keep route patterns focused on locating an operation rather than encoding every validation or permission rule. A successful match does not mean a database record exists or that the current caller may access it. Those are later boundaries. Organize related routes into an app URLconf and include it from the project so a reusable app does not hard-code its deployment prefix.

Converters establish limited input guarantees

A path converter such as int parses the matching path segment into an integer before invoking the view. A slug converter accepts a defined character shape, not a complete business identifier policy. A positive integer path can still identify a missing or unauthorized record. Choose converter and validation contracts deliberately and handle absence with an appropriate response, commonly a 404 for a missing resource. Do not turn converter success into trust for arbitrary database access. Trailing slash handling and redirect middleware can affect a request, so test the actual declared route instead of assuming every similar spelling reaches the same view with the same method.

Resolve a path in an isolated URL module

The first example declares its own URL patterns inside one complete program and resolves a known path. It does not import an application URLconf or contact a database. The resolved kwargs contain an integer because the converter performed that transformation. Calling the matched view still supplies the request argument explicitly in this demonstration. Resolution is a useful narrow test for pattern names and converter behavior, but it does not run middleware or prove a browser request works. A real application should also test unmatched paths and distinguish an unknown route from a known route whose resource is absent.

python Isolated executable example
from django.conf import settings
settings.configure(
    SECRET_KEY="synthetic-course-key",
    USE_I18N=False, USE_TZ=True,
    INSTALLED_APPS=[],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    DEFAULT_AUTO_FIELD="django.db.models.AutoField",
    ALLOWED_HOSTS=["testserver"],
)
import django
django.setup()

from django.http import HttpResponse
from django.urls import path, resolve

def detail(request, course_id):
    return HttpResponse(str(course_id), content_type="text/plain")

urlpatterns = [path("courses/<int:course_id>/", detail, name="course-detail")]
match = resolve("/courses/7/", urlconf=__name__)
print(match.url_name)
print(match.kwargs["course_id"], type(match.kwargs["course_id"]).__name__)
Expected output
course-detail
7 int

Resolution returns the named match and an integer argument. No record lookup or request middleware is implied.

Reverse names rather than copy path strings

The second example reverses a named route with a record id and includes an approved query value through Django 5.2’s reverse interface. A route name is a navigation contract that can survive a changed path prefix. Namespaces prevent unrelated apps from colliding on generic names such as detail. Pass arguments matching the route’s converter and required parameters; a missing or incompatible argument can raise NoReverseMatch. A reversed URL is not an authorization token. Templates, redirects, and tests should use the named contract while the server still validates identity and access when the resulting request arrives.

python Isolated executable example
from django.conf import settings
settings.configure(
    SECRET_KEY="synthetic-course-key",
    USE_I18N=False, USE_TZ=True,
    INSTALLED_APPS=[],
    DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
    DEFAULT_AUTO_FIELD="django.db.models.AutoField",
    ALLOWED_HOSTS=["testserver"],
)
import django
django.setup()

from django.http import HttpResponse
from django.urls import path, reverse

def detail(request, course_id):
    return HttpResponse("Local route")

urlpatterns = [path("courses/<int:course_id>/", detail, name="course-detail")]
print(reverse("course-detail", kwargs={"course_id": 7}, urlconf=__name__, query={"view": "summary"}))
Expected output
/courses/7/?view=summary

The name supplies the path and reverse encodes the query under the Django 5.2 API. The program performs no navigation.

Review path changes as interface changes

Test order-sensitive patterns, renamed views, namespaces, and links from the page that uses them. Avoid broad catch-all routes that accidentally hide a more specific endpoint. Keep external redirect destinations under an explicit allow policy instead of trusting a next query parameter; routing and safe redirect handling solve different questions. When a URL changes publicly, plan compatibility and redirect behavior, including whether preserving or changing the method is appropriate. This course’s routing programs only resolve and construct local paths. They do not establish deployment rewrites, proxy prefixes, or access controls, which need their own integration evidence.

Common errors and fixes

A valid route still returns a missing record

Why it happens
Path matching was confused with resource existence.
How to fix it
Look up the authorized resource and handle absence deliberately.
Prevent it next time
Test converter, existence, and permission separately.

A reverse call fails after a refactor

Why it happens
Its name, namespace, or arguments no longer match the pattern.
How to fix it
Compare the named route contract and provided kwargs.
Prevent it next time
Use named-route tests before publishing path changes.

A broad pattern shadows a specific route

Why it happens
Pattern ordering sends the path to an earlier match.
How to fix it
Reorder or narrow the competing patterns.
Prevent it next time
Include representative ambiguous paths in route tests.

Check your understanding

1. Does <int:course_id> authorize access to course 7?

Show worked solution

No. It establishes a parsed argument shape. The view must still locate the resource under its visibility scope and enforce the operation’s permission. A positive id can be absent or belong to someone else, so route tests and access tests need distinct assertions.

2. How can a reusable app avoid coupling links to /training/?

Show worked solution

Define app route names and an app namespace, include the URLconf at the chosen project prefix, and reverse the names from templates or code. The host can then move the prefix without rewriting every link, while tests confirm the resulting public URLs.

Key takeaways

  • Routing selects a view, not a permission decision.
  • Converters have bounded guarantees.
  • Names and namespaces make navigation maintainable.

Official references