Difficulty: Beginner
Function-based views (FBVs) are the simplest way to handle HTTP requests in Django. A view function takes an HttpRequest object as its first argument and returns an HttpResponse object. Everything that happens between receiving the request and returning the response - querying the database, processing forms, rendering templates - is your business logic.
The HttpRequest object contains all the information about the incoming request. request.method tells you if it is a GET, POST, PUT, DELETE, etc. request.GET is a dictionary-like object containing query string parameters. request.POST contains form data from POST requests. request.FILES contains uploaded files. request.user provides the currently authenticated user (or an AnonymousUser). request.session gives access to the session data.
The most common way to return a response is using the render() shortcut, which combines a template with context data and returns an HttpResponse. You pass the request, the template path, and a context dictionary. Django finds the template, renders it with the provided data, and wraps the result in an HttpResponse.
For redirects, use the redirect() shortcut, which returns an HttpResponseRedirect. You can pass it a URL string, a named URL pattern, or even a model instance (if the model has a get_absolute_url() method). After processing a form submission, you should always redirect to prevent duplicate form submissions on page refresh - this is known as the Post/Redirect/Get (PRG) pattern.
The get_object_or_404() and get_list_or_404() shortcuts are essential for views that display specific objects. They attempt to retrieve an object from the database and raise a 404 error if it does not exist, saving you from writing try/except blocks in every detail view.
FBVs handle different HTTP methods by checking request.method inside the function. A common pattern is to handle GET requests (display a form or data) and POST requests (process form submission) in the same view function using an if/else block. This is straightforward but can lead to complex functions when handling many HTTP methods or complex logic.
Django provides several decorator-based tools for FBVs. The @login_required decorator restricts access to authenticated users. The @require_http_methods decorator limits which HTTP methods the view accepts. The @csrf_exempt decorator disables CSRF protection (useful for API endpoints that use other authentication methods). These decorators keep your view functions clean by handling cross-cutting concerns.
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse
from .models import Article
# Simple text response
def hello(request):
return HttpResponse('Hello, World!')
# JSON response
def api_hello(request):
return JsonResponse({'message': 'Hello, World!', 'status': 'ok'})
# Render a template with context
def article_list(request):
articles = Article.objects.filter(is_published=True)
return render(request, 'blog/article_list.html', {
'articles': articles,
'total': articles.count(),
})
# Detail view with 404 handling
def article_detail(request, pk):
article = get_object_or_404(Article, pk=pk, is_published=True)
return render(request, 'blog/article_detail.html', {
'article': article,
})
HttpResponse returns raw text. JsonResponse returns JSON. render() combines a template with context data. get_object_or_404() returns the object or raises a 404 error if not found.
from django.shortcuts import render, redirect
from .forms import ArticleForm
def article_create(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save(commit=False)
article.author = request.user
article.save()
return redirect('blog:article-detail', pk=article.pk)
else:
form = ArticleForm()
return render(request, 'blog/article_form.html', {
'form': form,
})
This follows the POST/Redirect/Get pattern. GET requests display an empty form. POST requests validate and save the form, then redirect on success. If validation fails, the form re-renders with error messages.
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods
from django.shortcuts import render, redirect, get_object_or_404
from .models import Article
from .forms import ArticleForm
@login_required
@require_http_methods(['GET', 'POST'])
def article_edit(request, pk):
article = get_object_or_404(Article, pk=pk, author=request.user)
if request.method == 'POST':
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
form.save()
return redirect('blog:article-detail', pk=article.pk)
else:
form = ArticleForm(instance=article)
return render(request, 'blog/article_form.html', {
'form': form,
'article': article,
})
@login_required redirects unauthenticated users to the login page. @require_http_methods limits the view to specific HTTP methods. Passing instance=article to the form pre-fills it with existing data for editing.
def debug_request(request):
info = {
'method': request.method,
'path': request.path,
'full_path': request.get_full_path(),
'is_secure': request.is_secure(),
'is_ajax': request.headers.get('X-Requested-With') == 'XMLHttpRequest',
'user': str(request.user),
'is_authenticated': request.user.is_authenticated,
'content_type': request.content_type,
'GET_params': dict(request.GET),
'POST_data': dict(request.POST),
'cookies': dict(request.COOKIES),
}
return JsonResponse(info)
The request object contains everything about the HTTP request. request.GET has query parameters, request.POST has form data, request.user has the current user, request.COOKIES has cookies, and request.headers has HTTP headers.
FBV, HttpRequest, HttpResponse, render, redirect