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

如何在Django中正确处理错误?含全局异常及DetailView实现示例

Django全局异常处理实现方案(重点覆盖DetailView)

一、自定义全局异常处理器

先配置全局异常处理函数,统一捕获所有未被视图局部处理的异常,完成日志、响应等标准化逻辑。

  1. 在项目utils/目录下创建exception_handlers.py,编写处理函数:
import logging
import sys
from django.http import JsonResponse
from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist
from django.views.debug import technical_500_response
from django.conf import settings

logger = logging.getLogger(__name__)

def custom_exception_handler(request, exception):
    # 记录异常上下文,辅助排查
    context = {
        'path': request.path,
        'user': request.user.username if request.user.is_authenticated else 'anonymous',
        'request_params': request.GET.dict() if request.method == 'GET' else request.POST.dict()
    }

    # 针对性处理ObjectDoesNotExist异常
    if isinstance(exception, ObjectDoesNotExist):
        logger.warning(f"对象不存在: {str(exception)} | 上下文: {context}")
        # 根据请求类型返回对应响应
        if request.accepts('application/json'):
            return JsonResponse({'error': '请求的资源不存在'}, status=404)
        else:
            return render(request, '404.html', status=404)
    
    # 处理其他未捕获的异常
    logger.error(f"未处理异常: {str(exception)} | 上下文: {context}", exc_info=True)
    
    # 开发环境返回详细错误,生产环境返回通用提示
    if settings.DEBUG:
        return technical_500_response(request, *sys.exc_info())
    else:
        if request.accepts('application/json'):
            return JsonResponse({'error': '服务器内部错误'}, status=500)
        else:
            return render(request, '500.html', status=500)
  1. 在项目settings.py中替换默认处理器:
handler500 = 'utils.exception_handlers.custom_exception_handler'
handler404 = 'utils.exception_handlers.custom_exception_handler'

二、DetailView的异常处理(重点)

DetailView默认通过get_object()调用get()获取对象,会抛出DoesNotExist异常,提供两种落地方案:

方案1:重写单个DetailView的get_object方法

在目标视图中局部处理业务日志后,将异常抛给全局处理器:

from django.views.generic.detail import DetailView
from django.core.exceptions import ObjectDoesNotExist
import logging
from .models import Profile

logger = logging.getLogger(__name__)

class ProfileDetailView(DetailView):
    model = Profile
    template_name = 'profile/detail.html'

    def get_object(self, queryset=None):
        current_user_object = self.request.user
        try:
            return Profile.objects.get(user_connected_id=current_user_object)
        except ObjectDoesNotExist:
            logger.info(f"用户{current_user_object.id}关联的Profile不存在")
            # 抛出异常,交给全局处理器处理响应
            raise

方案2:封装Mixin复用给所有DetailView

多个DetailView需要统一逻辑时,用Mixin实现代码复用:

import logging
from django.core.exceptions import ObjectDoesNotExist

logger = logging.getLogger(__name__)

class DetailViewExceptionMixin:
    def get_object(self, queryset=None):
        try:
            return super().get_object(queryset)
        except ObjectDoesNotExist as e:
            logger.info(f"[{self.__class__.__name__}] 查询对象失败: {str(e)}")
            # 抛给全局处理器处理响应
            raise

# 使用时继承Mixin
class ProfileDetailView(DetailViewExceptionMixin, DetailView):
    model = Profile
    template_name = 'profile/detail.html'

三、其他视图类型的异常处理

1. 函数视图

用装饰器统一处理,或直接包裹try-except:

import logging
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse

logger = logging.getLogger(__name__)

def exception_handler_decorator(view_func):
    def wrapper(request, *args, **kwargs):
        try:
            return view_func(request, *args, **kwargs)
        except ObjectDoesNotExist as e:
            logger.info(f"函数视图异常: {str(e)}")
            raise
        except Exception as e:
            logger.error(f"函数视图未处理异常: {str(e)}")
            raise
    return wrapper

# 应用装饰器
@exception_handler_decorator
def profile_view(request):
    current_user_object = request.user
    current_profile = Profile.objects.get(user_connected_id=current_user_object)
    # 视图业务逻辑...

2. 普通类视图(非DetailView)

重写dispatch方法捕获全请求周期的异常:

from django.views.generic.base import View
import logging
from django.core.exceptions import ObjectDoesNotExist

logger = logging.getLogger(__name__)

class BaseExceptionHandlingView(View):
    def dispatch(self, request, *args, **kwargs):
        try:
            return super().dispatch(request, *args, **kwargs)
        except ObjectDoesNotExist as e:
            logger.info(f"类视图异常: {str(e)}")
            raise
        except Exception as e:
            logger.error(f"类视图未处理异常: {str(e)}")
            raise

# 继承使用
class SomeCustomView(BaseExceptionHandlingView):
    def get(self, request):
        # 视图业务逻辑...

四、全局处理器除日志外的必要操作

  1. 返回规范HTTP状态码:比如ObjectDoesNotExist对应404,服务器错误对应500,参数错误对应400,遵循HTTP协议规范。
  2. 返回友好错误响应:区分API和模板视图,API返回结构化JSON,模板视图返回定制化错误页面,避免泄露敏感信息。
  3. 记录完整上下文:包括请求路径、用户身份、请求参数、异常栈信息,便于后续问题排查。
  4. 过滤敏感信息:生产环境禁止将异常栈、数据库连接信息等返回给前端,只返回通用提示。
  5. 可选异常报警:针对严重异常(如数据库连接失败),配置邮件、企业微信等报警渠道,及时通知开发人员。

内容的提问来源于stack exchange,提问作者Тв0р0бушек

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 07:33:13