You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django/DRF中实现业务逻辑异常到API异常的可复用映射?

最优方案:利用DRF自定义全局异常处理器

要实现业务异常到DRF API异常的统一映射,最简洁可复用的方式是扩展DRF的全局异常处理机制,无需在每个视图中重复编写异常捕获代码。以下是具体实现步骤:


1. 规范业务异常类定义

首先为业务异常创建统一基类,便于后续批量处理;同时给每个具体异常绑定对应的HTTP状态码:

from django.http import Http404
from rest_framework import status

# 业务异常基类
class BusinessLogicException(Exception):
    def __init__(self, message: str, status_code: int = status.HTTP_400_BAD_REQUEST):
        self.message = message
        self.status_code = status_code
        super().__init__(message)

# 具体业务异常
class DeactivatedUser(BusinessLogicException):
    def __init__(self, message: str, user):
        super().__init__(message, status.HTTP_403_FORBIDDEN)
        self.user = user

class NotVerifiedEmail(BusinessLogicException):
    def __init__(self, message: str):
        super().__init__(message, status.HTTP_400_BAD_REQUEST)

2. 编写自定义全局异常处理器

在项目的utils目录下创建exception_handlers.py,实现DRF异常处理器的扩展:

import logging
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth.models import User

logger = logging.getLogger(__name__)

def custom_exception_handler(exc, context):
    # 先调用DRF默认处理器,处理框架原生异常
    response = exception_handler(exc, context)

    # 处理自定义业务异常
    if isinstance(exc, BusinessLogicException):
        # 统一记录业务异常日志
        logger.info(
            f"业务逻辑异常: {exc.message}",
            exc_info=True,
            extra={"request": context["request"], "user": getattr(exc, "user", None)}
        )
        return Response(
            {"detail": exc.message},
            status=exc.status_code
        )
    
    # 处理User.DoesNotExist异常
    if isinstance(exc, User.DoesNotExist):
        identifier = context["request"].data.get("identifier")
        logger.info(
            f"未找到匹配标识符的用户: {identifier}",
            exc_info=True,
            extra={"request": context["request"]}
        )
        return Response(
            {"detail": "Invalid input."},
            status=status.HTTP_404_NOT_FOUND
        )

    return response

3. 配置DRF使用自定义处理器

在项目的settings.py中,指定DRF使用我们的自定义异常处理器:

REST_FRAMEWORK = {
    # 替换默认异常处理器
    'EXCEPTION_HANDLER': 'your_project_name.utils.exception_handlers.custom_exception_handler',
    # 其他DRF配置...
}

4. 简化视图代码

现在视图中无需再编写try-except块,直接调用业务逻辑方法即可,异常会被全局处理器自动捕获并转换为DRF响应:

# 视图中使用代码(简化后)
user = User.bll.get_user_with_identifier(identifier, allow_username=False)

方案优势

  • 代码复用:避免在每个视图中重复编写异常捕获逻辑
  • 集中管理:所有异常映射规则统一维护在一处,便于后续修改和扩展
  • 解耦分层:业务层只负责抛出业务语义的异常,API层统一处理HTTP响应转换
  • 日志统一:可在全局处理器中统一记录异常日志,保持业务层代码简洁

内容的提问来源于stack exchange,提问作者Bad Boy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 22:20:18