Django Views
The view layer is responsible for processing requests and returning responses — it is the core of Django’s business logic. This article covers how to write function-based views (FBV) and class-based views (CBV), how to use response objects such as HttpResponse, render, redirect, and JsonResponse, and how to work with the request object’s common attributes and file uploads.
The View Layer
What Is a View Function?
A view function (or simply “view”) belongs to Django’s view layer and is defined by default in views.py. It is a function that handles web request information and returns a response.
Defining a View Function
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
# Every view function takes an HttpRequest object as its first argument, conventionally named "request".
# The name of the view function does not matter; Django does not require any particular naming convention.How render Works Internally
render is a shortcut that combines Template and Context into one call:
from django.template import Template, Context
res = Template('<h1>{{ user }}</h1>')
con = Context({'user': {'username': 'jason', 'password': 123}})
ret = res.render(con)
print(ret)
return HttpResponse(ret)The JsonResponse Object
JSON is a language-agnostic data format that enables data exchange between the front end and back end.
# JavaScript equivalents:
# JSON.stringify() ↔ json.dumps()
# JSON.parse() ↔ json.loads()
import json
from django.http import JsonResponse
def ab_json(request):
user_dict = {'username': 'json666', 'password': '123', 'hobby': 'girl'}
l = [111, 222, 333, 444, 555]
# Option 1: manually serialize and return
# json_str = json.dumps(user_dict, ensure_ascii=False)
# return HttpResponse(json_str)
# Option 2: use JsonResponse — reads source code for usage details
# return JsonResponse(user_dict, json_dumps_params={'ensure_ascii': False})
# To serialize non-dict objects, set safe=False
# return JsonResponse(l, safe=False)
# By default only dicts can be serialized; other types require safe=FalseForm File Upload and Backend Handling
"""
To upload a file through an HTML form:
1. method must be set to POST
2. enctype must be set to multipart/form-data
"""
def ab_file(request):
if request.method == 'POST':
# request.POST only retrieves ordinary key/value data; files are not included
print(request.FILES) # retrieve file data
# <MultiValueDict: {'file': [<InMemoryUploadedFile: example.jpg (image/jpeg)>]}>
file_obj = request.FILES.get('file') # file object
print(file_obj.name)
with open(file_obj.name, 'wb') as f:
for line in file_obj.chunks(): # chunks() reads the file in pieces (recommended)
f.write(line)
return render(request, 'form.html')Frontend HTML:
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>username: <input type="text" name="username"></p>
<p>file: <input type="file" name="file"></p>
<input type="submit">
</form>The request Object’s Common Methods and Attributes
request.method # HTTP method: 'GET', 'POST', etc.
request.POST # POST data (form-encoded)
request.GET # Query string parameters
request.FILES # Uploaded files
request.body # Raw binary data sent by the browser
request.path # URL path without query string, e.g. /app01/ab_file/
request.path_info # Same as request.path in most cases
request.get_full_path() # Full path including query string, e.g. /app01/ab_file/?username=json
# Example output:
print(request.path) # /app01/ab_file/
print(request.path_info) # /app01/ab_file/
print(request.get_full_path()) # /app01/ab_file/?username=jsonFBV vs. CBV
Django views can be written as functions (FBV — Function-Based Views) or as classes (CBV — Class-Based Views).
Function-Based View (FBV)
def index(request):
return HttpResponse('index')Class-Based View (CBV)
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.MyLogin.as_view()),
]
# views.py
from django.views import View
class MyLogin(View):
def get(self, request):
return render(request, 'form.html')
def post(self, request):
return HttpResponse('POST method')CBV automatically dispatches to the correct method based on the HTTP request method, without needing an if request.method == 'GET' branch.
CBV Source Code Analysis
Understanding how CBV works internally helps you use and extend it correctly.
The key insight is in urls.py:
path('login/', views.MyLogin.as_view())
# This is functionally equivalent to:
# path('login/', views.view) # just like FBV
# CBV and FBV are the same at the routing level: both map a URL to a function's memory address.as_view() is a class method (@classonlymethod) that returns a plain function called view:
@classonlymethod
def as_view(cls, **initkwargs):
"""
cls is our own class, e.g. MyLogin.
Main entry point for a request-response process.
"""
def view(request, *args, **kwargs):
self = cls(**initkwargs) # instantiate our class
# self = MyLogin(**initkwargs) — creates an instance of our class
return self.dispatch(request, *args, **kwargs)
"""
When reading Python source code, always remind yourself of the
attribute/method lookup order for OOP:
1. Look on the instance itself
2. Look on the class that produced the instance
3. Look on parent classes (MRO)
Rule: whenever you see "self.something" in source code,
always ask yourself: who is "self" at this moment?
"""
return viewThe core of CBV is the dispatch method:
def dispatch(self, request, *args, **kwargs):
# Convert the HTTP method to lowercase and check if it is allowed
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
"""
Reflection: using a string to look up an attribute or method on an object.
handler = getattr(instance_of_our_class, 'get', fallback_if_not_found)
handler = the get() method defined in our class
"""
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
# Automatically calls the correct method (e.g. get or post)Summary of CBV execution flow (memorize this — no source code needed):
- A request arrives; Django calls the
viewfunction returned byas_view(). viewinstantiates our class and callsself.dispatch(request).dispatchconvertsrequest.methodto lowercase (e.g.'get').- It uses
getattr(self, 'get', fallback)— reflection — to find the corresponding method. - It calls that method and returns the response.
This is why defining a get method on your CBV class means it is called for GET requests, and post for POST requests, with no extra conditional logic needed.