Paramclasses Academy - Blog

Tutorials Details

←
Post 19 of 29
→

Django Class-Based Views (CBVs): TemplateView, ListView, DetailView, CreateView, UpdateView, and DeleteView

Django Class-Based Views (CBVs): TemplateView, ListView, DetailView, CreateView, UpdateView, and DeleteView

October 21, 2026

Introduction

In Django, Class-Based Views (CBVs) provide a structured and reusable way to handle web requests. Instead of writing every view as a function, developers can use Python classes to organize application logic and reduce repetitive code.

Django provides several built-in generic class-based views, such as TemplateView, ListView, DetailView, CreateView, UpdateView, and DeleteView. These views simplify common tasks like displaying pages, listing database records, showing individual records, and performing CRUD operations.

In this module, you will learn how to implement Class-Based Views in a Django project and connect them with URLs, templates, models, and forms.

What You Will Learn

  • What Class-Based Views are and how they work.

  • Difference between Function-Based Views (FBVs) and Class-Based Views (CBVs).

  • How to use TemplateView to display static pages.

  • How to use ListView to display multiple database records.

  • How to use DetailView to display a single record.

  • How to use CreateView to create new records.

  • How to use UpdateView to update existing records.

  • How to use DeleteView to delete records safely.

  • How to configure URLs, templates, and success redirects.

  • Best practices for using CBVs in real-world Django applications.

1. What Are Class-Based Views?

A Class-Based View (CBV) is a Django view written as a Python class rather than a function. It allows developers to organize request-handling logic into methods.

Example of a Function-Based View:

from django.shortcuts import render

def home(request):
    return render(request, "home.html")

Equivalent Class-Based View:

from django.views import View
from django.shortcuts import render

class HomeView(View):
    def get(self, request):
        return render(request, "home.html")

In urls.py, a class-based view must be connected using .as_view().

from django.urls import path
from .views import HomeView

urlpatterns = [
    path("", HomeView.as_view(), name="home"),
]

Important: The .as_view() method converts the class into a callable view that Django can use to handle incoming requests.

2. Function-Based Views vs Class-Based Views

Function-Based Views (FBVs) use Python functions to process requests. Class-Based Views (CBVs) use classes and methods to organize request-handling behavior.

Feature Function-Based Views Class-Based Views
Structure Functions Classes
HTTP methods Usually handled with conditions or decorators Methods such as get() and post()
Code reuse Functions and decorators Inheritance and mixins
Generic CRUD operations Often require more code Built-in generic views
Best suited for Simple or highly customized logic Reusable and standard workflows

Both approaches are useful. Choose the one that makes your code easier to understand and maintain.

3. Using TemplateView

TemplateView is used to display a template without requiring a database query.

views.py

from django.views.generic import TemplateView

class HomeView(TemplateView):
    template_name = "home.html"

urls.py

from django.urls import path
from .views import HomeView

urlpatterns = [
    path("", HomeView.as_view(), name="home"),
]

templates/home.html

<!DOCTYPE html>
<html>
<head>
    <title>Home Page</title>
</head>
<body>
    <h1>Welcome to Django</h1>
    <p>This page is rendered using TemplateView.</p>
</body>
</html>

Explanation:

  • TemplateView is imported from django.views.generic.

  • template_name specifies which template Django should render.

  • HomeView.as_view() connects the class to the URL.

4. Using ListView to Display Database Records

ListView retrieves multiple objects from a model and makes them available to a template.

Suppose your application contains a Student model.

models.py

from django.db import models

class Student(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    course = models.CharField(max_length=100)

    def __str__(self):
        return self.name

Run the migrations after creating the model:

python manage.py makemigrations
python manage.py migrate

views.py

from django.views.generic import ListView
from .models import Student

class StudentListView(ListView):
    model = Student
    template_name = "students/student_list.html"
    context_object_name = "students"
    ordering = ["name"]

urls.py

from django.urls import path
from .views import StudentListView

urlpatterns = [
    path(
        "students/",
        StudentListView.as_view(),
        name="student_list"
    ),
]

templates/students/student_list.html

<h1>Student List</h1>

<ul>
    {% for student in students %}
        <li>
            {{ student.name }} -
            {{ student.email }} -
            {{ student.course }}
        </li>
    {% empty %}
        <li>No students found.</li>
    {% endfor %}
</ul>

Important concepts:

  • model specifies the model to query.

  • template_name specifies the template.

  • context_object_name defines the variable used in the template.

  • ordering determines the default ordering of records.

  • {% empty %} displays a message when the queryset has no records.

5. Using DetailView to Display One Record

DetailView displays information about a single database object. By default, Django looks for an object using the URL's pk or slug parameter.

views.py

from django.views.generic import DetailView
from .models import Student

class StudentDetailView(DetailView):
    model = Student
    template_name = "students/student_detail.html"
    context_object_name = "student"

urls.py

from django.urls import path
from .views import StudentDetailView

urlpatterns = [
    path(
        "students/<int:pk>/",
        StudentDetailView.as_view(),
        name="student_detail"
    ),
]

templates/students/student_detail.html

<h1>Student Details</h1>

<p>Name: {{ student.name }}</p>
<p>Email: {{ student.email }}</p>
<p>Course: {{ student.course }}</p>

<a href="{% url 'student_list' %}">Back to Students</a>

Example URL:

http://127.0.0.1:8000/students/1/

Here, 1 is the primary key of the student record.

Note: If the requested record does not exist, Django normally returns a 404 response.

6. Using CreateView to Add Records

CreateView automatically handles displaying a model form and saving a new database record.

views.py

from django.urls import reverse_lazy
from django.views.generic import CreateView
from .models import Student

class StudentCreateView(CreateView):
    model = Student
    fields = ["name", "email", "course"]
    template_name = "students/student_form.html"
    success_url = reverse_lazy("student_list")

urls.py

from django.urls import path
from .views import StudentCreateView

urlpatterns = [
    path(
        "students/add/",
        StudentCreateView.as_view(),
        name="student_add"
    ),
]

templates/students/student_form.html

<h1>Add Student</h1>

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}

    <button type="submit">Save Student</button>
</form>

How it works:

  1. A GET request displays the form.

  2. The user enters student information.

  3. A POST request submits the form.

  4. Django validates the submitted data.

  5. If the data is valid, Django saves the record.

  6. The user is redirected to the student list.

Important: Always include {% csrf_token %} in internal POST forms to protect against Cross-Site Request Forgery (CSRF).

7. Using UpdateView to Edit Records

UpdateView loads an existing record into a form and saves changes after successful validation.

views.py

from django.urls import reverse_lazy
from django.views.generic import UpdateView
from .models import Student

class StudentUpdateView(UpdateView):
    model = Student
    fields = ["name", "email", "course"]
    template_name = "students/student_form.html"
    success_url = reverse_lazy("student_list")

urls.py

from django.urls import path
from .views import StudentUpdateView

urlpatterns = [
    path(
        "students/<int:pk>/edit/",
        StudentUpdateView.as_view(),
        name="student_edit"
    ),
]

The same student_form.html template can be used for both creating and updating a student.

Add an Edit Link to the List Template

{% for student in students %}
    <p>
        {{ student.name }}

        <a href="{% url 'student_edit' student.pk %}">
            Edit
        </a>
    </p>
{% endfor %}

Explanation: Django retrieves the student using the primary key, displays the existing values, validates the updated information, and saves the changes.

8. Using DeleteView to Delete Records

DeleteView displays a confirmation page and deletes an object after the user submits the confirmation form.

views.py

from django.urls import reverse_lazy
from django.views.generic import DeleteView
from .models import Student

class StudentDeleteView(DeleteView):
    model = Student
    template_name = "students/student_confirm_delete.html"
    success_url = reverse_lazy("student_list")

urls.py

from django.urls import path
from .views import StudentDeleteView

urlpatterns = [
    path(
        "students/<int:pk>/delete/",
        StudentDeleteView.as_view(),
        name="student_delete"
    ),
]

templates/students/student_confirm_delete.html

<h1>Delete Student</h1>

<p>
    Are you sure you want to delete
    {{ object.name }}?
</p>

<form method="post">
    {% csrf_token %}

    <button type="submit">Confirm Delete</button>
    <a href="{% url 'student_list' %}">Cancel</a>
</form>

Security Note: Deletion should use a POST request, not a link that immediately deletes the record. In real applications, protect deletion views with appropriate authentication and permissions.

9. Understanding reverse_lazy()

Django's reverse_lazy() resolves a URL by its name. It is commonly used for class attributes such as success_url, where the URL may not need to be resolved immediately.

Example:

from django.urls import reverse_lazy

success_url = reverse_lazy("student_list")

This redirects the user to the URL registered with the name student_list after a successful operation.

Difference between reverse() and reverse_lazy():

  • reverse() resolves a named URL when called.

  • reverse_lazy() delays URL resolution until it is needed.

10. Understanding get_queryset()

The get_queryset() method allows you to customize which database records a view retrieves.

Example: Display only students enrolled in the Python course.

from django.views.generic import ListView
from .models import Student

class PythonStudentListView(ListView):
    model = Student
    template_name = "students/student_list.html"
    context_object_name = "students"

    def get_queryset(self):
        return Student.objects.filter(
            course__icontains="Python"
        ).order_by("name")

Explanation:

  • filter() selects matching records.

  • course__icontains performs a case-insensitive partial match.

  • order_by("name") sorts the results alphabetically.

This approach is useful when implementing search filters, category pages, and role-specific data listings.

11. Passing Extra Context to a Template

You can use get_context_data() to add additional information to the template context.

from django.views.generic import ListView
from .models import Student

class StudentListView(ListView):
    model = Student
    template_name = "students/student_list.html"
    context_object_name = "students"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context["total_students"] = self.get_queryset().count()

        return context

Display the count in the template:

<h2>Total Students: {{ total_students }}</h2>

Important: Call super().get_context_data(**kwargs) so that Django's existing context values remain available.

12. Protecting Class-Based Views with LoginRequiredMixin

Some pages should only be accessible to authenticated users. Django provides LoginRequiredMixin for protecting class-based views.

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from .models import Student

class StudentListView(LoginRequiredMixin, ListView):
    model = Student
    template_name = "students/student_list.html"
    context_object_name = "students"
    login_url = "/accounts/login/"

Important: Place LoginRequiredMixin before the generic view class in the inheritance list.

Configure the login URL in settings.py if you prefer to use a named login route:

LOGIN_URL = "login"

The value must match the name of your configured login URL.

Security Best Practice: Authentication alone does not mean a user is authorized to view or modify every record. Use permission checks, appropriate mixins, or queryset restrictions to prevent unauthorized access.

13. Common Mistakes in Class-Based Views

Mistake 1: Forgetting .as_view()

Incorrect:

path("students/", StudentListView)

Correct:

path("students/", StudentListView.as_view())

Mistake 2: Using the Wrong Template Path

If the view specifies:

template_name = "students/student_list.html"

The template must be located at the corresponding path within a configured template directory or application template directory.

Mistake 3: Missing success_url

CreateView, UpdateView, and DeleteView need a valid redirect destination or an appropriate URL-generation method. Configure success_url or implement the relevant behavior.

Mistake 4: Forgetting CSRF Protection

Internal POST forms should include:

{% csrf_token %}

Mistake 5: Allowing Unauthorized Record Changes

Do not assume that hiding an Edit or Delete link protects the record. Enforce authorization in the view itself.

14. Frequently Asked Questions (FAQs)

Q1. What is a Class-Based View in Django?

A Class-Based View is a view implemented using a Python class. It organizes request handling through methods and supports inheritance and reusable behavior.

Q2. What is the purpose of .as_view()?

It converts a class-based view into a callable function that Django can invoke for incoming requests.

Q3. What is the difference between ListView and DetailView?

ListView displays multiple records, whereas DetailView displays one record.

Q4. Can CreateView and UpdateView use the same template?

Yes. Both can use the same form template, such as students/student_form.html.

Q5. Why is reverse_lazy() commonly used with CBVs?

It delays URL resolution, making it suitable for class attributes such as success_url.

Q6. Can Class-Based Views handle GET and POST requests?

Yes. The base View class supports HTTP method handlers such as get() and post(). Generic editing views already implement common form-handling behavior.

Q7. Are Class-Based Views always better than Function-Based Views?

No. CBVs are helpful for reusable patterns and standard workflows, while FBVs can be simpler for small or highly customized tasks. Choose the approach that best fits the requirement.

15. Django Interview Questions and Answers

Q1. Name six commonly used generic Class-Based Views.

Answer: TemplateView, ListView, DetailView, CreateView, UpdateView, and DeleteView.

Q2. What is the purpose of context_object_name?

Answer: It defines the variable name used to access the view's main object or queryset in the template.

Q3. What is get_queryset() used for?

Answer: It customizes the records retrieved by a view, such as filtering students by course or user.

Q4. What does get_context_data() do?

Answer: It adds extra variables to the template context while retaining the default context provided by Django.

Q5. How do you restrict a CBV to authenticated users?

Answer: Use LoginRequiredMixin before the generic view class in the inheritance list.

Q6. How does DeleteView work?

Answer: It retrieves the selected object, displays a confirmation template, and deletes the object when a valid POST request confirms the operation.

Q7. What is the difference between pk and slug in a DetailView URL?

Answer: pk usually identifies an object by its primary key, while slug identifies it using a URL-friendly text field. The URL configuration and view must be set up consistently.

16. Practical Assignment

Create a Student Management System using Django Class-Based Views.

Requirements:

  1. Create a Student model with name, email, and course fields.

  2. Create a homepage using TemplateView.

  3. Display all students using ListView.

  4. Show an individual student's details using DetailView.

  5. Add new students using CreateView.

  6. Edit existing students using UpdateView.

  7. Delete students using DeleteView with a confirmation page.

  8. Use reverse_lazy() for successful redirects.

  9. Add an Edit and Delete link to each student in the list.

  10. Protect the student management pages with authentication.

  11. Display the total number of students on the listing page.

  12. Test all URLs and verify the database records after each CRUD operation.

Expected Result:

You should have a working student management application that uses Django's generic Class-Based Views for the main CRUD workflow.

Conclusion

In this module, you learned how Django Class-Based Views (CBVs) simplify web application development. You explored TemplateView, ListView, DetailView, CreateView, UpdateView, and DeleteView, along with URL configuration, templates, queryset customization, extra context, redirects, and authentication.

These concepts are valuable when building maintainable Django applications such as student management systems, inventory applications, employee portals, and administrative dashboards.

In the next module, you will learn about Django REST Framework (DRF) fundamentals, including API concepts, serializers, API views, and building your first Django REST API.

←
Post 19 of 29
→