Python
类视图与通用视图
发布于 2026年7月23日
类视图与通用视图
函数视图直观明确,类视图(CBV)适合复用通用流程。本篇不要求把所有 View 都改成类,而是理解什么时候使用 ListView、DetailView、编辑视图和 Mixin。
一、最基础的 View
from django.http import HttpResponse
from django.views import View
class HealthView(View):
def get(self, request):
return HttpResponse("ok")
路由中必须调用 as_view():
path("health/", HealthView.as_view(), name="health")
as_view() 返回一个可调用对象,Django 再根据 HTTP 方法分派到 get()、post() 等方法。
二、列表和详情通用视图
from django.views.generic import DetailView, ListView
from .models import Message
class MessageListView(ListView):
model = Message
template_name = "notes/message_list.html"
context_object_name = "messages"
paginate_by = 10
def get_queryset(self):
queryset = super().get_queryset().select_related("owner")
keyword = self.request.GET.get("q", "").strip()
if keyword:
queryset = queryset.filter(content__icontains=keyword)
return queryset
class MessageDetailView(DetailView):
model = Message
template_name = "notes/message_detail.html"
context_object_name = "message"
get_queryset() 是控制可见数据和优化查询的重要位置。
三、创建和更新通用视图
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView
from .forms import MessageForm
class MessageCreateView(LoginRequiredMixin, CreateView):
model = Message
form_class = MessageForm
template_name = "notes/message_form.html"
def form_valid(self, form):
form.instance.owner = self.request.user
return super().form_valid(form)
class MessageUpdateView(LoginRequiredMixin, UpdateView):
model = Message
form_class = MessageForm
template_name = "notes/message_form.html"
def get_queryset(self):
return super().get_queryset().filter(owner=self.request.user)
模型可定义成功后的地址:
from django.urls import reverse
def get_absolute_url(self):
return reverse("notes:detail", kwargs={"pk": self.pk})
reverse_lazy() 适合类属性等模块加载阶段;方法内部通常使用 reverse()。
四、删除通用视图
from django.views.generic import DeleteView
class MessageDeleteView(LoginRequiredMixin, DeleteView):
model = Message
template_name = "notes/message_confirm_delete.html"
success_url = reverse_lazy("notes:list")
def get_queryset(self):
return super().get_queryset().filter(owner=self.request.user)
五、向模板增加上下文
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["page_title"] = "我的留言"
context["draft_count"] = self.request.user.messages.filter(
status="draft"
).count()
return context
必须先调用 super(),否则父类准备的 object、form 或分页信息会丢失。
六、自定义 Mixin
多个视图都需要限制数据归属时可以提取 Mixin:
class OwnerQuerySetMixin:
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(owner=self.request.user)
class MessageUpdateView(
LoginRequiredMixin,
OwnerQuerySetMixin,
UpdateView,
):
model = Message
form_class = MessageForm
Mixin 应职责单一,避免制造包含大量隐式行为的“万能基类”。多继承时要理解 Python MRO,并让每个重写方法正确调用 super()。
七、常用生命周期方法
| 方法 | 用途 |
|---|---|
dispatch() |
按 HTTP 方法分派,适合通用前置处理 |
get_queryset() |
限制和优化查询集 |
get_object() |
获取单个对象,通常优先改查询集 |
get_context_data() |
增加模板上下文 |
get_form_kwargs() |
给 Form 传额外参数 |
form_valid() |
表单校验成功后的处理 |
form_invalid() |
表单校验失败后的处理 |
get_success_url() |
动态生成成功跳转地址 |
调试 CBV 时,可从 URL 对应的类开始,沿请求类型找到 get()/post(),再查看使用的 Mixin 和生命周期方法。
八、什么时候用 FBV 或 CBV
适合函数视图:
- 流程短且独特。
- 需要非常直观地看到执行顺序。
- 团队刚开始学习 Django。
适合类视图:
- 标准列表、详情和编辑页面。
- 多个视图共享认证、权限或查询逻辑。
- 需要按 HTTP 方法拆分实现。
不要仅为了“高级”而使用 CBV。能清楚表达业务、容易测试和维护才是选择标准。
九、常见问题
- 路由报错:忘记调用
.as_view()。 - 登录限制无效:
LoginRequiredMixin的继承位置不合适。 - 模板变量不存在:
context_object_name与模板使用名称不一致。 - 成功保存后不知道跳转哪里:未定义
get_absolute_url()或success_url。 - 覆盖方法后分页/表单丢失:忘记调用
super()。
十、本篇检查清单
- 能把标准 CRUD 改写为通用类视图。
- 能使用
get_queryset()实现对象权限和查询优化。 - 能用
form_valid()写入当前用户。 - 理解 Mixin、MRO 和
super()的作用。 - 能根据业务复杂度选择 FBV 或 CBV。