下载工作台
Django Web 开发

类视图 CBV 与通用 CRUD

试读上半部分 · 解锁后可读全文

第 4 章 · 类视图 CBV 与通用 CRUD

本章目标:理解 Django 类视图(CBV) 的设计思想;熟练使用 ListView / CreateView / UpdateView / DeleteView 完成商品 CRUD;掌握 LoginRequiredMixinPermissionRequiredMixin;了解 Mixin 组合模式;能将 ch02~ch03 的函数视图重构为 CBV,并保持权限与表单行为一致。

学时建议:5~6 小时(含 2 小时跟练)

前置:完成 django-web ch01~ch03(ModelForm、登录、Group 权限)。


4.1 场景说明:减少重复的 CRUD 样板代码

ch02~ch03 用函数视图实现了商品的增删改查,每个视图都重复以下模式:

GET  → 构建 form / queryset → render
POST → 校验 → save / delete → redirect
权限 → @login_required + @permission_required

Django 通用类视图(GCBV) 把这些共性抽取为可复用类,通过声明 modelform_classtemplate_name 即可。

操作函数视图类视图
列表def product_listProductListView(ListView)
创建def product_createProductCreateView(CreateView)
编辑def product_editProductUpdateView(UpdateView)
删除手写 POST 确认ProductDeleteView(DeleteView)

4.2 CBV 请求分发:as_view()

path("create/", ProductCreateView.as_view(), name="product_create")

as_view() 返回一个函数,内部根据 request.method 调用不同方法:

HTTP 方法调用的方法典型用途
GETget()展示表单或列表
POSTpost()提交表单
PUT/PATCHput() / patch()REST 风格(少用)
DELETEdelete()删除确认

View 基类流程:

dispatch()  →  按 method 分派到 get/post/...
    ↓
get() / post()  →  调用 get_context_data()、form_valid() 等钩子
    ↓
render_to_response() / redirect

4.3 ListView:商品列表

catalog/views.py(CBV 版本,可与函数版二选一或并存教学):

from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import (
    CreateView,
    DeleteView,
    ListView,
    UpdateView,
)

from .forms import ProductForm
from .models import Product


class ProductListView(LoginRequiredMixin, ListView):
    model = Product
    template_name = "catalog/product_list.html"
    context_object_name = "products"
    paginate_by = 20  # ch06 详讲分页,此处先预留

    def get_queryset(self):
        qs = Product.objects.filter(is_active=True).select_related("category")
        return qs.order_by("-created_at")
属性作用
model自动提供 object_list / products
template_name模板路径
context_object_name模板中变量名
get_queryset()自定义过滤、排序

4.4 CreateView:新建商品

class ProductCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
    model = Product
    form_class = ProductForm
    template_name = "catalog/product_form.html"
    permission_required = "catalog.add_product"
    success_url = reverse_lazy("product_list")

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["title"] = "新建商品"
        ctx["submit_label"] = "创建"
        return ctx

    def form_valid(self, form):
        messages.success(self.request, f"商品「{form.instance.name}」创建成功。")
        return super().form_valid(form)

执行链post()form_valid()save()redirect(success_url)

钩子时机典型用途
get_context_data()渲染前追加 title、面包屑
form_valid()校验通过消息提示、发信号
form_invalid()校验失败自定义错误处理
get_success_url()保存成功后动态跳转地址

4.5 UpdateView:编辑商品

class ProductUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
    model = Product
    form_class = ProductForm
    template_name = "catalog/product_form.html"
    permission_required = "catalog.change_product"
    success_url = reverse_lazy("product_list")

    def get_context_data(self, **kwargs):
        ctx = super().get_context_data(**kwargs)
        ctx["title"] = "编辑商品"
        ctx["submit_label"] = "保存"
        ctx["product"] = self.object
        return ctx

    def form_valid(self, form):
        messages.success(self.request, f"商品「{form.instance.name}」已更新。")
        return super().form_valid(form)

UpdateViewget() 时自动用 self.object(根据 pkslug_url_kwarg)填充表单。


4.6 DeleteView:删除商品

catalog/templates/catalog/product_confirm_delete.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>确认删除</title>
</head>
<body>
  <h1>确认删除商品?</h1>
  <p>将删除:<strong>{{ object.name }}</strong>({{ object.sku }})</p>
  <form method="post">
    {% csrf_token %}
    <button type="submit">确认删除</button>
    <a href="{% url 'product_list' %}">取消</a>
  </form>
</body>
</html>
class ProductDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
    model = Product
    template_name = "catalog/product_confirm_delete.html"
    permission_required = "catalog.delete_product"
    success_url = reverse_lazy("product_list")

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。