一、整体结构

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、表单处理
                        Logo

                        openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

                        更多推荐