URLconfs and function views

Django · Essentials · 12 min

Views are where requests become responses, and named URLs keep links correct as the site grows.

A view is a function that takes an HttpRequest and returns an HttpResponse. The URLconf maps paths to views:

urlpatterns = [path("posts/<int:pk>/", views.post_detail, name="post-detail")]

Path converters (str, int, slug, uuid, path) capture and convert parts of the URL into keyword arguments. Patterns have no leading slash and conventionally end with one; re_path is available for regular expressions.

Each app usually has its own urls.py, included from the project's: path("blog/", include("blog.urls")). Setting app_name = "blog" in the app's URLconf creates a namespace, so names are referenced as "blog:post-detail".

Never hard-code URLs. Build them from names: reverse("blog:post-detail", args=[3]) in Python, {% url 'blog:post-detail' post.pk %} in templates, and redirect("blog:post-detail", pk=3) as a shortcut.

Inside a view:

  • request.method, request.GET and request.POST (QueryDicts), request.headers, request.user
  • return HttpResponse, JsonResponse, redirect(...) or render(...)
  • get_object_or_404(Post, pk=pk) turns a missing row into a 404
  • raise Http404 yourself for other not-found cases

Decorators such as @require_POST or @require_http_methods(["GET", "POST"]) restrict methods and return 405 for others.

Example

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

app_name = "blog"
urlpatterns = [
    path("", views.post_list, name="list"),
    path("posts/<int:pk>/", views.post_detail, name="detail"),
]

# blog/views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.urls import reverse
from .models import Post

def post_list(request):
    q = request.GET.get("q", "")
    posts = Post.objects.filter(title__icontains=q)
    return JsonResponse({"results": [{"title": p.title, "url": reverse("blog:detail", args=[p.pk])} for p in posts]})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)       # 404 if missing
    return JsonResponse({"title": post.title})
# mysite/urls.py:  path("blog/", include("blog.urls"))  ->  /blog/posts/3/

Remember

  • path("route/<int:pk>/", view, name=...) maps URLs to views
  • include() + app_name give each app its own namespaced URLconf
  • Build URLs with reverse() and {% url %}, never by hand

Watch out for

  • Starting a pattern with a slash ("/posts/"), which never matches.

Check yourself

  1. With app_name = "blog" and path("posts/<int:pk>/", ..., name="detail") included under "blog/", what does reverse("blog:detail", args=[7]) return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.djangoproject.com/en/6.0/topics/http/urls/