Django 中间件 4 大钩子 & CBV vs FBV 对比实战

通过最小化 Demo 验证 Django 中间件的 4 个钩子函数,并对比类视图 (CBV) 与函数视图 (FBV) 的异同。


一、环境

项目 版本
Python 3.13
Django 6.0.5

项目结构:

复制代码
DjangoHook/
├── demo/
│   ├── middleware.py   ← 自定义中间件(4 钩子)
│   └── views.py        ← FBV + CBV 对比视图
├── screenshots/
└── middleware_demo.log  ← 中间件运行日志

二、中间件 4 个钩子函数

Django 中间件是请求/响应的"钩子链",可以在请求到达视图前/后、异常发生时插入自定义逻辑。

执行顺序遵循 洋葱模型:请求阶段从上到下穿过所有中间件,响应阶段反向穿回。

2.1 四个钩子一览

钩子 触发时机 返回值 执行方向
process_request(request) 请求进入,视图未确定 None 或 HttpResponse ↓ 正向
process_view(request, view_func, view_args, view_kwargs) 路由匹配后、视图执行前 None 或 HttpResponse ↓ 正向
process_exception(request, exception) 视图抛出异常时 None 或 HttpResponse ↑ 反向
process_response(request, response) 响应返回前 HttpResponse ↑ 反向

2.2 核心源码

python 复制代码
# demo/middleware.py
class DemoMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        self.process_request(request)            # 钩子1
        response = self.get_response(request)    # → 内部触发钩子2、3
        response = self.process_response(request, response)  # 钩子4
        return response

    def process_request(self, request):
        log(f"1. process_request --- {request.path}")

    def process_view(self, request, view_func, view_args, view_kwargs):
        log(f"2. process_view --- {view_func.__name__}")

    def process_exception(self, request, exception):
        log(f"3. process_exception --- {type(exception).__name__}: {exception}")

    def process_response(self, request, response):
        log(f"4. process_response --- {response.status_code}")
        return response

2.3 实验验证

分别请求正常视图和异常视图,观察中间件日志:

结论:

  • 正常路径 :process_request → process_view → 视图执行 → process_response
  • 异常路径 :process_request → process_view → 视图抛异常 → process_exception → process_response

浏览器截图如下------

正常请求 (FBV hello) :

异常请求 (FBV exception) :

2.4 洋葱模型图解

复制代码
  请求 ──────────────────────────────→ 响应
  ┌─────────────────────────────────────────┐
  │  1.process_request()    4.process_response()  │
  │         ↓                      ↑                │
  │  2.process_view()        3.process_exception()  │
  │         ↓                      ↑                │
  │      ┌──────────────────┐                    │
  │      │     视图函数      │                    │
  │      └──────────────────┘                    │
  └─────────────────────────────────────────┘

三、CBV vs FBV 对比

FBV (Function-Based View) 和 CBV (Class-Based View) 都能处理 HTTP 请求,核心差异在于 代码组织方式。

3.1 最简示例

python 复制代码
# ========== FBV ==========
def hello_fbv(request):
    return HttpResponse("Hello from FBV!")

# ========== CBV ==========
class HelloCBV(View):
    def get(self, request):
        return HttpResponse("Hello from CBV!")

浏览器截图:

FBV CBV

3.2 处理多种 HTTP 方法

python 复制代码
# ========== FBV: 手动判断 request.method ==========
@csrf_exempt
def api_fbv(request):
    if request.method == "GET":
        return JsonResponse({"method": "GET", "type": "FBV"})
    elif request.method == "POST":
        data = json.loads(request.body) if request.body else {}
        return JsonResponse({"method": "POST", "type": "FBV", "received": data})
    return JsonResponse({"error": "Method not allowed"}, status=405)

# ========== CBV: 方法名自动分发 ==========
@method_decorator(csrf_exempt, name='dispatch')
class ApiCBV(View):
    def get(self, request):
        return JsonResponse({"method": "GET", "type": "CBV"})

    def post(self, request):
        data = json.loads(request.body) if request.body else {}
        return JsonResponse({"method": "POST", "type": "CBV", "received": data})

3.3 对比总结

维度 FBV CBV
代码量 (简单场景) 更少 稍多
代码量 (多方法场景) 手动 if/elif 方法自动分发
HTTP 方法分发 手动判断 request.method 自动映射 get() → GET, post() → POST
复用方式 @decorator 继承 + Mixin
可读性 函数体膨胀 每个方法职责单一
Django 内置通用视图 不支持 ListView, DetailView 等

3.4 何时用哪个?

  • 逻辑简单、单一功能 → FBV,例如:重定向、简单 API、健康检查
  • CRUD 操作、多种 HTTP 方法 → CBV,例如:REST API 资源、表单处理
  • 需要复用 Django 内置视图 → CBV,例如:分页列表、详情页

四、路由配置

python 复制代码
# DjangoHook/urls.py
from django.urls import path
from demo import views

urlpatterns = [
    # FBV
    path('fbv/hello/',     views.hello_fbv,       name='fbv_hello'),
    path('fbv/api/',       views.api_fbv,         name='fbv_api'),
    path('fbv/exception/', views.exception_fbv,   name='fbv_exception'),

    # CBV
    path('cbv/hello/',     views.HelloCBV.as_view(),      name='cbv_hello'),
    path('cbv/api/',       views.ApiCBV.as_view(),        name='cbv_api'),
    path('cbv/exception/', views.ExceptionCBV.as_view(),  name='cbv_exception'),
]

注意 CBV 必须调用 .as_view() 将类转换为可调用的视图函数。


相关推荐
Carl_奕然2 分钟前
【机器视觉】最强算法之:3D高斯泼溅(3D Gaussian Splatting)
人工智能·python·算法·目标检测·计算机视觉·3d
小亮_money1 小时前
Agent开发工程师-Python环境搭建
人工智能·python
isfox1 小时前
Python3 线程:多任务并发编程详解
python
Michelle80231 小时前
第1周摸底测试
python
通问AI2 小时前
【实战】企业口径一致性检查:用 Python 对齐官网/招聘平台/投标文件三个来源的成立日期与注册地
开发语言·python
AI直播技术杂谈2 小时前
九点整那场,讲品顺序是前一天下午就锁定的
网络·python·ai·秒播
青少儿编程课堂2 小时前
蓝桥杯青少组·全国青少年信息素养·电子学会Scratch考级:校园智能抢答器项目解析
c++·python·算法·bfs·信息学竞赛
BD_Marathon2 小时前
【Python】函数_关键字参数
python
aa小小2 小时前
从0到1:Windows 本地部署 Qwen3 + Flask 接口(RAG 学习路线第1周踩坑实录)
python
镜子AI2 小时前
镜子AI工程实践:用熵权法 + TOPSIS 做多方案选型排序(零依赖 Python)
开发语言·人工智能·python