Django Blog Cbv
In this chapter, you will learn Django's Class-Based Views (CBV) to refactor the homepage and detail page with more concise code.
* * *
## FBV vs CBV
So far, all our views have been written using functions (Function-Based View, FBV).
Django also provides Class-Based Views (CBV), which encapsulate view logic in classes.
| Feature | FBV (Function-Based View) | CBV (Class-Based View) |
| --- | --- | --- |
| Code Amount | Flexible, but common logic needs to be repeated | After inheriting generic views, only a few lines of code needed |
| Readability | Linear flow, clear logic | Inheritance chain needs to be traced, but becomes clear once familiar |
| Reusability | Encapsulated through functions | Combined through Mixins (Django's feature) |
| Applicable Scenarios | Pages with simple logic and clear flow | Standard CRUD pattern pages |
| HTTP Method Dispatch | Manual if request.method == 'POST' | Automatic dispatch to get() / post() methods |
There is no absolute advantage or disadvantage between the two. Django projects typically use a mix of FBV and CBV: FBV for complex logic, CBV for standard CRUD operations.
* * *
## ListView β List Page Refactoring
The homepage's index view essentially does: query article list β render template.
For this kind of standardized logic, Django's `ListView` has already been written for you.
## Example
# File path: blog/views.py
from django.views.generic import ListView
from django.db.models import Q
from .models import Post, Category
class PostListView(ListView):
"""Blog homepage: inherits ListView, displays article list"""
model = Post # Specify model
template_name ='blog/index.html'# Specify template (default: blog/post_list.html)
context_object_name ='posts'# Variable name used in template (default: object_list)
paginate_by =12# 12 items per page (pagination)
ordering =['-created_at']# Ordering
def get_queryset(self):
"""Override query method: support category filtering + keyword search"""
queryset =super().get_queryset()
# Category filtering
self.category_slug=self.request.GET.get('category','')
if self.category_slug:
queryset = queryset.filter(category__slug=self.category_slug)
# Keyword search
self.keyword=self.request.GET.get('q','')
if self.keyword:
queryset = queryset.filter(
Q(title__icontains=self.keyword) |
Q(summary__icontains=self.keyword)
)
return queryset
def get_context_data(self, **kwargs):
"""Override context method: inject additional data into template"""
context =super().get_context_data(**kwargs)
context['categories']= Category.objects.all()
context['category_slug']=self.category_slug
context['keyword']=self.keyword
context['title']='TUTORIAL Home - Home'
return context
Compare the code amount before and after refactoring: FBV ~40 lines β CBV ~30 lines, and the logic is clearly divided into different methods.
* * *
## DetailView β Detail Page Refactoring
## Example
# File path: blog/views.py Add new
from django.views.generic import DetailView
class PostDetailView(DetailView):
"""Article detail page: inherits DetailView"""
model = Post
template_name ='blog/post_detail.html'
context_object_name ='post'
# pk_url_kwarg: parameter name for primary key passed in URL (default is pk, explicitly declared here)
pk_url_kwarg ='pk'
def get_context_data(self, **kwargs):
context =super().get_context_data(**kwargs)
context['title']= f'{self.object.title} - TUTORIAL Home'
return context
* * *
## Update URL Configuration
The CBV routingway of writing is slightly different from FBV β you need to call `.as_view()`.
## Example
# File path: blog/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns =[
# CBV: add .as_view() after the class to convert it to a view function
path('', views.PostListView.as_view(), name='index'),
path('post//', views.PostDetailView.as_view(), name='post_detail'),
# Other views remain unchanged
path('register/', views.register, name='register'),
path('login/', auth_views.LoginView.as_view(
template_name='blog/login.html',
redirect_authenticated_user=True
), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('post//favorite/', views.toggle_favorite, name='toggle_favorite'),
]
> Why does CBV use `.as_view()`? Django's URL configuration expects a callable (function). `.as_view()` converts the class-based view into a callable that conforms to Django's view function signature, internally responsible for automatically dispatching based on HTTP methods (GET/POST) to the class's get() or post() methods.
* * *
## Common Generic Views Overview
| View | Default Template Name | Purpose |
| --- | --- | --- |
| ListView | modelname_list
YouTip