4大钩子函数&验证CBV和FBV
中间件(Middleware)是 Django 请求/响应处理过程中的一个轻量级、低级的”插件”系统。它是一个处理管道,每个请求和响应都会经过中间件的处理。请求预处理(校验、过滤、日志)视图预处理(权限检查、参数注入)响应后处理(修改响应头、内容压缩)异常处理(统一错误页面)请求到达v[__init__] 服务器启动时执行一次v[process_request] 按注册顺序从上到下执行vURL 路
一、整体结构
django_middleware_demo/
├── django_middleware_demo/ # 项目配置
│ ├── settings.py # ✅ 已注册 app + 自定义中间件
│ └── urls.py # ✅ 主路由配置
├── middleware_app/ # 中间件演示
│ ├── middleware_demo.py # ✅ 6 大钩子函数完整实现
│ ├── views.py # ✅ 首页 + 异常测试视图
│ ├── urls.py # ✅ 路由
│ └── templates/middleware_app/
│ └── index.html # ✅ 可视化首页
├── view_demo/ # CBV vs FBV 对比
│ ├── views.py # ✅ FBV 4 个 + CBV 6 个视图
│ ├── urls.py # ✅ 全部路由
│ └── templates/view_demo/ # ✅ 8 个模板页面
└── README.md # ✅ 完整的 Markdown 文档
二、Django 中间件 4 大钩子函数
2.1 什么是中间件
中间件(Middleware)是 Django 请求/响应处理过程中的一个轻量级、低级的”插件”系统。它是一个处理管道,每个请求和响应都会经过中间件的处理。
中间件的作用:
- 请求预处理(校验、过滤、日志)
- 视图预处理(权限检查、参数注入)
- 响应后处理(修改响应头、内容压缩)
- 异常处理(统一错误页面)
2.2 钩子函数 1:__init__ 初始化方法
执行时机: Web 服务器启动时执行一次(开发模式下每次请求都会执行,因为 Django 开发服务器会自动重载)。
作用: 进行一次性初始化配置,如加载配置文件、建立数据库连接池等。
完整代码实现:
# middleware_app/middleware_demo.py
from django.utils.deprecation import MiddlewareMixin
class MiddlewareFourHooks(MiddlewareMixin):
def __init__(self, get_response):
"""
__init__ 初始化方法
参数:
- get_response: 下一个中间件或视图的响应处理函数
执行时机:
- 服务器启动时执行一次
"""
super().__init__(get_response)
print("=" * 60)
print("[__init__] 中间件初始化完成 - 服务器启动时执行")
print("=" * 60)
2.3 钩子函数 2:process_request 请求预处理
执行时机: 请求到达 Django 后,路由匹配之前执行。按 MIDDLEWARE 列表的注册顺序从上到下执行。
作用:
- 请求合法性校验(IP 黑名单、Token 验证)
- 请求日志记录
- 请求数据预处理
返回值:
None:正常处理,请求继续传递给下一个中间件或路由HttpResponse:直接返回响应,不再执行后续中间件和视图
完整代码实现:
# middleware_app/middleware_demo.py
import time
def process_request(self, request: HttpRequest):
"""
process_request - 请求预处理
参数:
- request: HttpRequest 对象
返回值:
- None: 继续处理
- HttpResponse: 直接返回响应
"""
request.middleware_start_time = time.time()
print("-" * 60)
print(f"[process_request] 请求预处理 - 路径: {request.path}")
print(f"[process_request] 请求方法: {request.method}")
user_agent = request.META.get("HTTP_USER_AGENT", "未知")
print(f"[process_request] 用户代理: {user_agent[:50]}...")
return None
2.4 钩子函数 3:process_view 视图预处理
执行时机: 路由匹配成功之后,视图函数执行之前。按 MIDDLEWARE 列表的注册顺序从上到下执行。
作用:
- 视图权限校验
- 向视图注入额外参数
- 在视图执行前进行最后的检查
参数:
request: HttpRequest 对象view_func: 将要执行的视图函数view_args: URL 中捕获的位置参数列表view_kwargs: URL 中捕获的关键字参数字典
完整代码实现:
# middleware_app/middleware_demo.py
def process_view(self, request: HttpRequest, view_func, view_args, view_kwargs):
"""
process_view - 视图预处理
参数:
- request: HttpRequest 对象
- view_func: 将要执行的视图函数
- view_args: URL 位置参数
- view_kwargs: URL 关键字参数
返回值:
- None: 继续执行视图
- HttpResponse: 直接返回响应
"""
print(f"[process_view] 视图预处理 - 视图函数: {view_func.__name__}")
print(f"[process_view] 视图参数: args={view_args}, kwargs={view_kwargs}")
view_name = view_func.__name__
if view_name == "fbv_demo_view":
print(f"[process_view] 检测到 FBV 视图: {view_name}")
elif hasattr(view_func, "view_class"):
print(f"[process_view] 检测到 CBV 视图: {view_func.view_class.__name__}")
return None
2.5 钩子函数 4:process_template_response 模板响应处理
执行时机: 视图返回 TemplateResponse 对象时执行。在 process_response 之前执行。
作用:
- 向模板上下文添加额外的变量
- 修改模板响应的内容
- 对模板响应进行后处理
注意: 仅当视图返回 TemplateResponse 对象时才会触发。如果视图返回普通的 HttpResponse,此方法不会执行。
完整代码实现:
# middleware_app/middleware_demo.py
import time
def process_template_response(self, request: HttpRequest, response):
"""
process_template_response - 模板响应处理
参数:
- request: HttpRequest 对象
- response: TemplateResponse 对象
返回值:
- 必须返回实现了 render() 方法的响应对象
"""
print("[process_template_response] 模板响应处理 - 开始渲染模板")
if hasattr(response, "context_data"):
extra_context = {
"middleware_processed_at": time.strftime("%Y-%m-%d %H:%M:%S"),
"middleware_message": "这条信息来自 process_template_response 钩子函数",
}
response.context_data.update(extra_context)
print(f"[process_template_response] 已向模板上下文添加额外数据")
print("[process_template_response] 模板响应处理完成")
return response
2.6 钩子函数 5:process_exception 异常处理
执行时机: 视图函数抛出异常时执行。按 MIDDLEWARE 列表的注册顺序从下到上执行。
作用:
- 统一异常处理
- 自定义错误页面
- 异常日志记2.7 钩子函数 6:
process_response响应后处理
执行时机: 视图处理完成后,响应返回给客户端之前。按 MIDDLEWARE 列表的注册顺序从下到上执行。
作用:
- 修改响应头(添加 CORS 头、安全头等)
- 响应内容压缩
- 请求耗时统计
- 响应日志记录
完整代码实现:
# middleware_app/middleware_demo.py
import time
def process_response(self, request: HttpRequest, response):
"""
process_response - 响应后处理
参数:
- request: HttpRequest 对象
- response: HttpResponse 对象
返回值:
- 必须返回 HttpResponse 对象
"""
start_time = getattr(request, "middleware_start_time", None)
if start_time:
duration = time.time() - start_time
print(f"[process_response] 请求处理耗时: {duration:.4f} 秒")
response["X-Request-Duration"] = f"{duration:.4f}s"
print(f"[process_response] 响应状态码: {response.status_code}")
print(f"[process_response] 响应内容类型: {response.get('Content-Type', '未知')}")
print(f"[process_response] 响应处理完成 - 返回给客户端")
print("-" * 60)
return response
2.8 中间件执行顺序总结
请求到达
|
v
[__init__] 服务器启动时执行一次
|
v
[process_request] 按注册顺序从上到下执行
|
v
URL 路由匹配
|
v
[process_view] 按注册顺序从上到下执行
|
v
视图函数执行
|
v
[process_template_response] 仅 TemplateResponse 触发
|
v
[process_exception] 视图抛出异常时触发(从下到上)
|
v
[process_response] 按注册顺序从下到上执行
|
v
响应返回给客户端
中间件注册配置(settings.py):
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'middleware_app.middleware_demo.MiddlewareFourHooks', # 自定义中间件
]
三、CBV vs FBV 对比实战
3.1 定义方式对比
| 对比维度 | FBV(基于函数的视图) | CBV(基于类的视图) |
|---|---|---|
| 定义方式 | 使用 def 定义函数 |
使用 class 定义类,继承 View |
| 参数传递 | 通过函数参数接收 request |
通过方法参数接收 request |
| 路由配置 | path('url/', views.func) |
path('url/', views.Class.as_view()) |
| 代码风格 | 过程式编程 | 面向对象编程 |
FBV 定义:
# FBV:使用函数定义
def fbv_demo_view(request):
context = {
"view_type": "FBV (Function-Based View)",
"features": ["简洁直观", "适合简单逻辑"],
}
return render(request, "view_demo/fbv_demo.html", context)
CBV 定义:
# CBV:使用类定义
from django.views import View
class CBVDemoView(View):
template_name = "view_demo/cbv_demo.html"
def get(self, request):
context = {
"view_type": "CBV (Class-Based View)",
"features": ["支持继承", "适合复杂逻辑"],
}
return render(request, self.template_name, context)
3.2 HTTP 方法处理对比
| 对比维度 | FBV | CBV |
|---|---|---|
| GET 请求 | if request.method == "GET": |
def get(self, request): |
| POST 请求 | elif request.method == "POST": |
def post(self, request): |
| PUT 请求 | elif request.method == "PUT": |
def put(self, request): |
| DELETE 请求 | elif request.method == "DELETE": |
def delete(self, request): |
| 代码结构 | 使用 if/elif 分支 | 使用独立方法 |
FBV 处理不同 HTTP 方法:
def fbv_article_list(request):
if request.method == "GET":
return render(request, "view_demo/fbv_articles.html", {"articles": articles})
elif request.method == "POST":
# 处理 POST 请求
new_article = {
"id": len(articles) + 1,
"title": request.POST.get("title", "未命名"),
}
articles.append(new_article)
return render(request, "view_demo/fbv_articles.html",
{"articles": articles, "message": "添加成功"})
CBV 处理不同 HTTP 方法:
class CBVArticleListView(View):
template_name = "view_demo/cbv_articles.html"
def get(self, request):
return render(request, self.template_name, {"articles": articles})
def post(self, request):
new_article = {
"id": len(articles) + 1,
"title": request.POST.get("title", "未命名"),
}
articles.append(new_article)
return render(request, self.template_name,
{"articles": articles, "message": "添加成功"})
3.3 装饰器使用对比
| 对比维度 | FBV | CBV |
|---|---|---|
| 使用方式 | 直接在函数上方加 @decorator |
使用 @method_decorator 包装 |
| 语法简洁度 | 非常简洁 | 稍复杂,需导入 method_decorator |
| 灵活性 | 只能装饰整个函数 | 可装饰 dispatch 或特定方法 |
FBV 装饰器:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET"])
def fbv_article_detail(request, article_id):
article = articles.get(article_id)
if not article:
return HttpResponse("文章不存在", status=404)
return render(request, "view_demo/fbv_article_detail.html", {"article": article})
CBV 装饰器:
from django.utils.decorators import method_decorator
class CBVArticleDetailView(View):
@method_decorator(require_http_methods(["GET"]))
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, article_id):
article = self.get_article_data().get(article_id)
if not article:
return HttpResponse("文章不存在", status=404)
return render(request, self.template_name, {"article": article})
3.4 代码组织与复用对比
| 对比维度 | FBV | CBV |
|---|---|---|
| 代码组织 | 通过函数拆分和导入实现复用 | 通过类继承和 Mixin 实现复用 |
| 代码复杂度 | 简单逻辑时更直观 | 复杂逻辑时更清晰 |
| 可测试性 | 函数测试简单直观 | 可继承测试类 |
| 社区通用性 | DRF 中仍广泛使用 | Django 内置通用视图推荐使用 |
3.5 继承与 Mixin 特性对比
Mixin 是 CBV 独有的强大特性,允许将功能模块化组合:
class LoggingMixin:
"""为 CBV 添加日志功能"""
def dispatch(self, request, *args, **kwargs):
print(f"[LoggingMixin] 请求: {request.method} {request.path}")
return super().dispatch(request, *args, **kwargs)
class JSONResponseMixin:
"""为 CBV 添加 JSON 响应能力"""
def render_to_json_response(self, context, **response_kwargs):
return JsonResponse(context, **response_kwargs)
# 通过多重继承组合多个 Mixin 的功能
class CBVAdvancedView(LoggingMixin, JSONResponseMixin, View):
def get(self, request):
data = {"message": "Mixin 组合演示", "method": "GET"}
return self.render_to_json_response(data)
def post(self, request):
data = {"message": "Mixin 处理 POST", "method": "POST"}
return self.render_to_json_response(data)
FBV 无法直接实现 Mixin 模式,需要通过装饰器嵌套或函数组合来模拟,代码可读性和复用性均不如 CBV。
四、运行说明
4.1 环境要求
- Python 3.8+
- Django 5.x
4.2 访问地址
| 功能 | URL |
|---|---|
| 项目首页 | http://127.0.0.1:8000/ |
| 中间件首页 | http://127.0.0.1:8000/middleware/ |
| 中间件异常测试 | http://127.0.0.1:8000/middleware/trigger-error/ |
| FBV 基础页 | http://127.0.0.1:8000/views/fbv/ |
| FBV 文章列表 | http://127.0.0.1:8000/views/fbv/articles/ |
| FBV 文章详情 | http://127.0.0.1:8000/views/fbv/articles/1/ |
| FBV 搜索 | http://127.0.0.1:8000/views/fbv/search/ |
| FBV 异常测试 | http://127.0.0.1:8000/views/fbv/error/ |
| CBV 基础页 | http://127.0.0.1:8000/views/cbv/ |
| CBV 文章列表 | http://127.0.0.1:8000/views/cbv/articles/ |
| CBV 文章详情 | http://127.0.0.1:8000/views/cbv/articles/1/ |
| CBV 搜索 | http://127.0.0.1:8000/views/cbv/search/ |
| CBV Mixin 演示 | http://127.0.0.1:8000/views/cbv/advanced/ |
| CBV 异常测试 | http://127.0.0.1:8000/views/cbv/error/ |
五、效果展示







六、CBV vs FBV 最终对比总结
| 对比维度 | FBV | CBV |
|---|---|---|
| 定义方式 | def 函数 |
class 类,继承 View |
| HTTP 方法分发 | if request.method == "..." |
get() / post() 等方法 |
| 装饰器使用 | 语法简单,直接 @decorator |
需 @method_decorator |
| 代码复用 | 函数提取 + 装饰器 | 类继承 + Mixin |
| 代码组织 | 适合简单逻辑 | 适合复杂业务 |
| 学习曲线 | 低,入门友好 | 中,需理解 OOP |
| Django 内置支持 | 装饰器辅助 | 丰富的 generic views |
| 适用场景 | 简单页面、API 端点 | 复杂 CRUD、表单处理 |
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)