Challenge 2: Protect a View — Possible Solution ==================================================================== # catalog/views.py from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from .forms import BookForm @login_required def book_create(request): if request.method == "POST": form = BookForm(request.POST) if form.is_valid(): form.save() return redirect("book-list") else: form = BookForm() return render(request, "catalog/book_form.html", {"form": form}) WHAT HAPPENS FOR AN ANONYMOUS REQUEST ------------------------------------------ When a request arrives at /books/new/ (or wherever book_create is mounted) WITHOUT an authenticated session, @login_required intercepts it before the view function's own code ever runs. Django responds with an HTTP 302 redirect to the URL configured in settings.LOGIN_URL (which defaults to "/accounts/login/"), and appends a "?next=" query parameter containing the ORIGINAL URL the user tried to reach — for example: HTTP/1.1 302 Found Location: /accounts/login/?next=/books/new/ This means that after the user successfully logs in, the login view can read that "next" parameter and redirect them straight back to /books/new/ — the page they originally wanted — rather than dropping them on a generic homepage. The book_create view function's own body (the form-handling logic) is never executed at all for the anonymous request; the redirect happens entirely within the decorator, before dispatch. WHY THIS WORKS -------------- - @login_required wraps the view function and checks request.user.is_authenticated before allowing the wrapped function to run at all — a logged-in user's request passes through untouched, while an anonymous request is short-circuited into the redirect described above. - Because this check happens via a decorator rather than a manual `if not request.user.is_authenticated: return redirect(...)` line inside the view, the exact same one-line protection can be applied consistently to any number of views without repeating that boilerplate check in each one. - LOGIN_URL is a project-wide setting (in settings.py), so every @login_required-protected view across the entire project redirects to the same, centrally configured login page — changing where the login page lives means updating one setting, not every view.