如何在Django中正确处理错误?含全局异常及DetailView实现示例
Django全局异常处理实现方案(重点覆盖DetailView)
一、自定义全局异常处理器
先配置全局异常处理函数,统一捕获所有未被视图局部处理的异常,完成日志、响应等标准化逻辑。
- 在项目
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)
- 在项目
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): # 视图业务逻辑...
四、全局处理器除日志外的必要操作
- 返回规范HTTP状态码:比如
ObjectDoesNotExist对应404,服务器错误对应500,参数错误对应400,遵循HTTP协议规范。 - 返回友好错误响应:区分API和模板视图,API返回结构化JSON,模板视图返回定制化错误页面,避免泄露敏感信息。
- 记录完整上下文:包括请求路径、用户身份、请求参数、异常栈信息,便于后续问题排查。
- 过滤敏感信息:生产环境禁止将异常栈、数据库连接信息等返回给前端,只返回通用提示。
- 可选异常报警:针对严重异常(如数据库连接失败),配置邮件、企业微信等报警渠道,及时通知开发人员。
内容的提问来源于stack exchange,提问作者Тв0р0бушек
相关产品推荐
相关产品推荐

