浏览知识库目录

Python

类视图与通用视图

类视图与通用视图

函数视图直观明确,类视图(CBV)适合复用通用流程。本篇不要求把所有 View 都改成类,而是理解什么时候使用 ListViewDetailView、编辑视图和 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(),否则父类准备的 objectform 或分页信息会丢失。


六、自定义 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。

上一篇:用户认证与权限控制 | 下一篇:管理后台定制