Mastering Django Views: Advanced Patterns, Requests, and Responses

A view in Django is a Python callable that takes a web request and returns a web response. The response can be HTML, a redirect, an error, an XML document, or an image. The logic can live anywhere inside your project, but by convention veiws are placed in a views.py file within an app or project directory.

Crafting a Basic View

Here is a function-based view that delivers the current server time as HTML:

from django.http import HttpResponse
import datetime

def server_time_view(request):
    current_moment = datetime.datetime.now()
    content = f"<html><body>Current server time: {current_moment}.</body></html>"
    return HttpResponse(content)

Breakdown:

  • We import HttpResponse from django.http and the standard datetime library.
  • server_time_view is the view function. Every view function receives an HttpRequest instance as its first argument, conventionally named request.
  • The function builds an HttpResponse object containing the rendered content and returns it. Views are always responsible for returning an HttpResponse.

Django handles the flow: when a page is requested, a new HttpRequest object is created, populated with metadata, and passed to the matching view.

Function-Based vs Class-Based Views

You can implement views as functions (FBV) or as classes (CBV).

FBV Example for creating a class record:

def create_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "create_class.html")

CBV Equivalent:

from django.views import View

class ClassCreateView(View):
    def get(self, request):
        return render(request, "create_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

Remember to update urls.py for a CBV:

url(r'^create_class/$', views.ClassCreateView.as_view()),

Applying Decorators to Views

Decorators on FBVs

FBVs are plain functions, so standard decorator syntax works:

def timeit(method):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = method(*args, **kwargs)
        print(f"Execution time: {time.time() - start:.4f}s")
        return result
    return wrapper

@timeit
def create_class(request):
    if request.method == "POST":
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")
    return render(request, "create_class.html")

Decorators on CBVs

Since class methods differ from standalone functions, use method_decorator to convert a function decorator:

from django.views import View
from django.utils.decorators import method_decorator

class ClassCreateView(View):
    @method_decorator(timeit)
    def get(self, request):
        return render(request, "create_class.html")

    def post(self, request):
        class_name = request.POST.get("class_name")
        models.Classes.objects.create(name=class_name)
        return redirect("/class_list/")

For applying logic across all HTTP methods (GET, POST, etc.), override dispatch:

class ProtectedView(View):
    def dispatch(self, request, *args, **kwargs):
        print('Pre-processing logic')
        response = super().dispatch(request, *args, **kwargs)
        print('Post-processing logic')
        return response
    
    def get(self, request):
        return render(request, 'protected.html')
    
    def post(self, request):
        data = request.POST.get('user')
        return HttpResponse('Protected POST received')

The Request Object

When a request arrives, Django constructs an HttpRequest object and passes it to the view as request. Key attributes and methods include:

  • method: HTTP verb (GET, POST, etc.) in uppercase.
  • GET / POST: Dictionary-like objects holding GET/POST parameters (use request.POST.getlist('key') for multi-value fields like checkboxes).
  • body: Raw request body as bytes.
  • FILES: Contains uploaded file data (only populated for POST with multipart/form-data, otherwise an empty dict-like object).
  • META: Python dictionary of HTTP headers (e.g., CONTENT_LENGTH, REMOTE_ADDR, HTTP_HOST).
  • user: Represents the logged-in user (AnonymousUser if not authenticated).
  • session: Read/write dictionary for session data.
  • get_host(): Returns the host header (e.g., 127.0.0.1:8000).
  • get_full_path(): URL path plus query string.
  • is_ajax(): Returns True for XMLHttpRequest calls (checks HTTP_X_REQUESTED_WITH).

Handling File Uploads

def handle_upload(request):
    if request.method == "POST":
        uploaded_file = request.FILES["file"]
        file_name = uploaded_file.name
        with open(file_name, "wb") as destination:
            for chunk in uploaded_file.chunks():
                destination.write(chunk)
        return HttpResponse("Upload completed.")

The Response Object

Every view constructs and returns an HttpResponse. You can pass a string and configure headers:

from django.http import HttpResponse

response = HttpResponse("Page content here.", content_type="text/plain")
response['X-Custom-Header'] = 'custom-value'
del response['X-Custom-Header']

Key Attributes:

  • content: The response body.
  • charset: Encoding.
  • status_code: HTTP status code.

JsonResponse

A subclass of HttpResponse for JSON APIs:

from django.http import JsonResponse

def json_handler(request):
    payload = {'status': 'active', 'items': [1, 2, 3]}
    return JsonResponse(payload)  # safe=True by default for dicts

# For non-dict data:
return JsonResponse([10, 20, 30], safe=False)

Shortcut Functions

render()

Wraps template loading and rendering into a single call:

from django.shortcuts import render

def profile_page(request):
    context = {'username': 'JohnDoe', 'active': True}
    return render(request, 'profile.html', context)

redirect()

Returns an HTTP redirect. Accepts a model instance, a view name, or a string path:

from django.shortcuts import redirect

def go_to_home(request):
    return redirect('/home/')

def go_to_detail(request):
    obj = MyModel.objects.get(pk=1)
    return redirect(obj)                    # calls obj.get_absolute_url()

def go_to_named_view(request):
    return redirect('dashboard-view', user='guest') # reverses URL

To issue a permanent redirect (301) instead of a temporary one (302), set permanent=True:

return redirect('/new-location/', permanent=True)

A 302 redirect does not change the search engine's indexed URL, while a 301 passes the ranking to the destination.

Tags: Django views CBV FBV request

Posted on Fri, 08 May 2026 14:02:06 +0000 by andreiga