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.GETandrequest.POST(QueryDicts),request.headers,request.user- return
HttpResponse,JsonResponse,redirect(...)orrender(...) get_object_or_404(Post, pk=pk)turns a missing row into a 404- raise
Http404yourself 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.