Django & Python ← Back to blog

Django URL Routing: How This Portfolio Is Wired Together

26 April 2026 · Matt

A walkthrough of the root urlpatterns in hello_world/urls.py and how each app plugs in.

The Root URL File

Every Django project has a root URL configuration. In this portfolio it lives at hello_world/urls.py and acts as a switchboard — incoming requests are matched against a list of patterns and dispatched to the right app.

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path("",               include("pages.urls")),
    path("admin/",         admin.site.urls),
    path("media-system/",  include("media_system.urls")),
    path("todo/",          include("todo.urls")),
    path("waes-project-b/",include("waes_project_b.urls")),
    path("waes-chat-e/",   include("waes_chat_e.urls")),
    path("waes-weather/",  include("waes_weather.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

The include() function defers matching to each app's own urls.py. This keeps apps self-contained — you can reorder or remove an app without touching the others.

The pages App

The root path ("") is handled by the pages app, which serves the homepage. Because it's first in the list and has an empty prefix, it captures bare / requests before anything else.

Static and Media Files in Development

The static() call at the bottom appends URL patterns for user-uploaded files. In production these are served by the web server (nginx/S3), but in development Django handles them directly.

# settings.py
MEDIA_URL  = "/media/"
MEDIA_ROOT = "/var/www/django_media"   # production
Tip: The static() helper only adds these patterns when DEBUG=True. In production, serving media through Django is too slow — point nginx or S3 at MEDIA_ROOT instead.

Per-App URL Files

Each app owns its own URL patterns. The media_system app, for example:

# media_system/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("",               views.index,            name="media-index"),
    path("upload/",        views.upload,           name="media-upload"),
    path("delete/<int:pk>/", views.delete,        name="media-delete"),
    path("generate/",      views.generate_ai_image,name="media-generate"),
]

The full URL for the generate endpoint becomes /media-system/generate/ because Django prepends the prefix from the root file.