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() 将类转换为可调用的视图函数。


相关推荐
caoerzhong17 分钟前
中小企业上 WMS 该先上哪几块:JeeWMS 开源 Java 仓库管理系统的分批上线清单
java·python·开源
正在走向自律32 分钟前
AI数据分析与可视化:从基础到应用实践
服务器·人工智能·python·机器学习·数据分析·pandas
databook1 小时前
从手动检查到自动监控:一个数据质量工作流的实现
后端·python·数据分析
北冥有鱼被烹3 小时前
砷化镓与磷化铟:光模块的地基——从化学键到AI缺货潮的底层逻辑
人工智能·python
for_ever_love__4 小时前
线性回归与梯度下降——从零手写一个模型
python·机器学习·线性回归·梯度下降
code_whiter5 小时前
7.自动化测试常用函数
python·功能测试
小园子的小菜5 小时前
Python协程深度解析:从原理演进到实战避坑
后端·python
砚底藏山河5 小时前
量化实战:截面因子有效性检验(IC 分析与分层回测)
java·python·金融·maven
GitFun6 小时前
给策略加了条-8%止损线,11年只触发1次
python·股票·量化交易
马六六i6 小时前
市面上正规的IP驱动产业新场景新工具有哪些
大数据·网络·python·tcp/ip