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) 请求进入,视图未确定 NoneHttpResponse ↓ 正向
process_view(request, view_func, view_args, view_kwargs) 路由匹配后、视图执行前 NoneHttpResponse ↓ 正向
process_exception(request, exception) 视图抛出异常时 NoneHttpResponse ↑ 反向
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_requestprocess_view → 视图执行 → process_response
  • 异常路径process_requestprocess_view → 视图抛异常 → process_exceptionprocess_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() 将类转换为可调用的视图函数。


相关推荐
李昊哲小课4 分钟前
fastapi sse websocket 奶茶店实时订单看板
人工智能·python·websocket·网络协议·fastapi·sse
2401_844582952 小时前
工具包:软件架构设计的实用技巧与经验分享
python
RFID固定资产管理系统2 小时前
适配媒体行业的固定资产管理软件有哪些功能与核心优势
大数据·人工智能·python·媒体
SunnyDays10113 小时前
Python 为 PowerPoint 添加动画:进入、退出、动作路径与文本动画(详解)
python·powerpoint·动画·动画效果·文本动画
难以怀瑾4 小时前
pytest.param`与 allure.dynamic.title()全解析
python
月光船幽幽5 小时前
Pytest配置实战:高效管理测试标记与覆盖
python·科技
leoZ2316 小时前
实战复盘:用 Claude Code 从零搭一个 GitHub PR 统计工具
java·人工智能·python·深度学习·自然语言处理·github·llama
夏天测6 小时前
Python 网络编程入门:从 Socket 底层到 HTTP 并发实战
python·socket·httpx·requests·tcp udp·python网络编程·爬虫基础
玉鸯7 小时前
多 Agent 并行时如何保证状态一致性?
分布式·python·agent
aGdF8E3gQ7 小时前
【Application Insights】采样率对Function App日志收集的影响和解决方法
python·flask·wpf