Function-Based Views
The URL patterns have picked a view. Now your code finally runs. A view is where the cookbook decides what to show: which recipes, in what order, with which template. The simplest kind of view is an ordinary Python function, and it has one strict contract.
The rule
Request in, response out: a view must always return an HttpResponse.
The smallest possible view:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello from the cookbook")Django calls it with an HttpRequest as the first argument, plus anything the URL captured. The request holds what the browser sent: request.method ("GET", "POST"), request.GET (query string values), request.POST (form data) and request.user.
Real views rarely build HTML by hand. They fetch data and hand it to a template with render():
# recipes/views.py
from django.shortcuts import get_object_or_404, render
from .models import Recipe
def recipe_list(request):
query = request.GET.get("q", "")
recipes = Recipe.objects.filter(title__icontains=query).order_by("-created")
return render(request, "recipes/recipe_list.html", {"recipes": recipes, "q": query})
def recipe_detail(request, slug):
recipe = get_object_or_404(Recipe, slug=slug)
return render(request, "recipes/recipe_detail.html", {"recipe": recipe})render(request, template, context)fills the template with the dictionary and returns anHttpResponse.get_object_or_404returns the object, or raisesHttp404, which Django turns into a proper 404 page instead of a crash.- Templates live in
recipes/templates/recipes/...; the repeated folder name keeps them apart from other apps' templates.
Other returns you will use: redirect("recipes:detail", slug=...) after saving something, and JsonResponse({...}) for data.
To handle a form, one view can branch on the method:
def recipe_new(request):
if request.method == "POST":
... # validate, save, then return redirect(...)
return render(request, "recipes/recipe_form.html")The shortcut
Write every view as three lines in your head: get input → get data → return a response. If any path through the function can end without a return, it is a bug.
Get input
request.GET.get("q", "")gives"soup", or an empty string if absent.
Forget the return on some branch and Django complains that the view "didn't return an HttpResponse object. It returned None instead."
Drills
Answer fast — trust the rule.
What must every Django view return?
For /recipes/no-such-dish/, what does get_object_or_404(Recipe, slug=slug) lead to?
How does a view read q from /recipes/?q=soup?
In render(request, "recipes/recipe_list.html", {"recipes": recipes}), what is the dictionary?
Remember
- Request in, response out: every path returns an
HttpResponse. - Get input, get data, return a response.
- Trap: a branch without
return, and hand-built HTML instead ofrender().
