Django & Flask Topic

Django Class-Based Views (CBVs)

This is one of the most powerful features of Django that can dramatically improve your productivity once you understand the concepts.

What are Class-Based Views?

Class-Based Views are an alternative to Function-Based Views (FBVs) that use Python classes instead of functions. They provide a structured way to handle HTTP requests and are perfect for common web development patterns.

Core CBVs Hierarchy

text

View (Base class)
├── TemplateView
├── RedirectView
├── FormView
└── Generic Display Views
    ├── ListView
    └── DetailView
└── Generic Editing Views
    ├── CreateView
    ├── UpdateView
    └── DeleteView

1. The Base View Class

Purpose: Foundation for all other CBVs

python

from django.views import View
from django.http import HttpResponse

class MyView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse("GET request handled!")
    
    def post(self, request, *args, **kwargs):
        return HttpResponse("POST request handled!")
    
    def put(self, request, *args, **kwargs):
        return HttpResponse("PUT request handled!")

URL configuration:

python

from django.urls import path
from .views import MyView

urlpatterns = [
    path('my-view/', MyView.as_view(), name='my-view'),
]

2. TemplateView

Purpose: Render a template without any complex logic

python

from django.views.generic import TemplateView

class HomePageView(TemplateView):
    template_name = "home.html"
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['latest_articles'] = Article.objects.all()[:5]
        context['title'] = "Welcome to Our Site"
        return context

3. ListView

Purpose: Display a list of objects

python

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

class ArticleListView(ListView):
    model = Article
    template_name = "articles/article_list.html"
    context_object_name = "articles"  # Default would be 'object_list'
    paginate_by = 10
    ordering = ['-published_date']
    
    def get_queryset(self):
        # Custom filtering
        queryset = super().get_queryset()
        category = self.request.GET.get('category')
        if category:
            queryset = queryset.filter(category__name=category)
        return queryset

Template context: object_list, articles (if context_object_name is set)

4. DetailView

Purpose: Display details of a single object

python

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

class ArticleDetailView(DetailView):
    model = Article
    template_name = "articles/article_detail.html"
    context_object_name = "article"  # Default would be 'object'
    slug_field = "slug"  # Use slug instead of pk
    slug_url_kwarg = "slug"  # URL parameter name
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['related_articles'] = Article.objects.filter(
            category=self.object.category
        ).exclude(pk=self.object.pk)[:3]
        return context

URL pattern:

python

path('article/<slug:slug>/', ArticleDetailView.as_view(), name='article-detail')

5. CreateView

Purpose: Handle form submission for creating new objects

python

from django.views.generic import CreateView
from django.urls import reverse_lazy
from .models import Article
from .forms import ArticleForm

class ArticleCreateView(CreateView):
    model = Article
    form_class = ArticleForm
    template_name = "articles/article_form.html"
    success_url = reverse_lazy('article-list')
    
    def form_valid(self, form):
        # Auto-set the author to current user
        form.instance.author = self.request.user
        return super().form_valid(form)

6. UpdateView

Purpose: Handle form submission for updating existing objects

python

from django.views.generic import UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages

class ArticleUpdateView(LoginRequiredMixin, UpdateView):
    model = Article
    form_class = ArticleForm
    template_name = "articles/article_form.html"
    
    def get_success_url(self):
        messages.success(self.request, "Article updated successfully!")
        return reverse('article-detail', kwargs={'slug': self.object.slug})
    
    def get_queryset(self):
        # Only allow authors to edit their own articles
        queryset = super().get_queryset()
        return queryset.filter(author=self.request.user)

7. DeleteView

Purpose: Handle object deletion with confirmation

python

from django.views.generic import DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

class ArticleDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Article
    template_name = "articles/article_confirm_delete.html"
    success_url = reverse_lazy('article-list')
    
    def test_func(self):
        # Only allow authors to delete their articles
        article = self.get_object()
        return article.author == self.request.user
    
    def delete(self, request, *args, **kwargs):
        messages.success(request, "Article deleted successfully!")
        return super().delete(request, *args, **kwargs)

URL Configuration for All Views

python

from django.urls import path
from .views import (
    ArticleListView, 
    ArticleDetailView, 
    ArticleCreateView,
    ArticleUpdateView, 
    ArticleDeleteView
)

urlpatterns = [
    path('', ArticleListView.as_view(), name='article-list'),
    path('article/<slug:slug>/', ArticleDetailView.as_view(), name='article-detail'),
    path('article/new/', ArticleCreateView.as_view(), name='article-create'),
    path('article/<slug:slug>/edit/', ArticleUpdateView.as_view(), name='article-update'),
    path('article/<slug:slug>/delete/', ArticleDeleteView.as_view(), name='article-delete'),
]

Using Mixins for Common Functionality

Mixins are reusable pieces of functionality that can be combined with CBVs:

python

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

class StaffRequiredMixin(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.is_staff

class AdminArticleCreateView(LoginRequiredMixin, StaffRequiredMixin, CreateView):
    model = Article
    fields = ['title', 'content', 'category']
    template_name = "articles/admin_article_form.html"
    success_url = reverse_lazy('article-list')

Key Advantages of CBVs

  1. Code Reuse: Inherit and extend functionality

  2. Structure: Consistent patterns for common tasks

  3. Built-in Features: Pagination, forms, success URLs

  4. Mixins: Composable behavior

  5. Less Boilerplate: Common patterns are handled automatically

Common Methods to Override

  • get_queryset() - Customize the object list

  • get_context_data() - Add extra context to templates

  • form_valid() - Custom behavior when form is valid

  • get_success_url() - Determine where to redirect after success

  • test_func() - For permission checks with UserPassesTestMixin

When to Use CBVs vs FBVs

Use CBVs for:

  • CRUD operations (Create, Read, Update, Delete)

  • Displaying lists or details of objects

  • Forms with standard patterns

  • When you need pagination, searching, filtering

Use FBVs for:

  • Very simple views

  • Highly custom behavior that doesn't fit CBV patterns

  • API endpoints (often better with DRF)

  • When the CBV would require too many overrides

This foundation will help you write cleaner, more maintainable Django code while significantly reducing boilerplate!

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?