Django restframework异常处理模块解析

Django restframework异常处理模块解析

主要的作用:

  • 处理我们逻辑异常,只要是通过路由进入我们的视图中的错误,都可以实现自定制的报错。
  • 例如,http://127.0.0.1:8000/api/v1/use/10/ 后面的10就是我们在业务逻辑代码所要取的第几条数据,但是我们的数据库中少于10条数据,那么页面就会产生报错,会出现404的报错,这是exception_handler这个句柄函数中默认处理的功能。

实现方法

我们通过具体的实例进行解析:

urls.py

urlpatterns = [
    re_path('^(?P<version>[v1|v2]+)/use/$', views.UseView.as_view()),
    re_path('^(?P<version>[v1|v2]+)/use/(?P<pk>\d+)/$', views.UseView.as_view()),
]

models.py

from django.db import models

# Create your models here.
class User(models.Model):
    SEX = (
        (1,'男'),
        (2,'女'),
    )
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)
    phone = models.CharField(max_length=32)
    sex = models.IntegerField(choices=SEX)
    icon = models.ImageField(upload_to='icon',default='icon/2.jpg')

    class Meta:
        db_table = 'usersex'
        verbose_name = '信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return '<<%s>>' % self.name

views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class UseView(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk: #pk大于数据数据库中的数据,会自动触发异常
            user_obj = models.User.objects.get(pk=pk)
            user_ser = serializser.UserSerializser(user_obj)
            return Response({
                'status':0,
                'msg':0,
                'results':user_ser.data
            })
        else:
            user_obj_list = models.User.objects.all()
            user_ser_list = serializser.UserSerializser(instance=user_obj_list,many=True) 
            print(user_ser_list)
            return Response({
                    'status':0,
                    'msg':0,
                    'results':user_ser_list.data
                })

settings.py

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'api.exception.exception.exception_handler',
}

api.exception.exception.exception_handler我们自定义exception_handler的路径

# author navigator
from rest_framework.views import exception_handler as drf_excepion_handler
from rest_framework.views import Response
def exception_handler(exc, context):
	response = drf_excepion_handler(exc,context)
	if response is None:
		ret = "%s-%s-%s"%(context["view"],context["request"].method,exc)
		return Response({ 
			'detail':ret
			})
	return response

上面的代码,一旦 urlpk 超出我们数据库中的值,就会自动触发我们自己设置的句柄

{
    "detail": "<api.views.UseView object at 0x000001D46254EBE0>-GET-User matching query does not exist."
}

如果只是想要设置全局的报错这些应该就足够。

源码解析

下面分析下源码

首先请求会触发到 APIView 中的 dispatch方法

def dispatch(self, request, *args, **kwargs):
        。。。

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)

        return self.response

当三大认证中出现报错,将会触发异常,所以我们应该关注 response = self.handle_exception(exc)

首先我们在 我们自己的类 UseView 去找有没有 handle_exception 这个方法,如果没有我们就到 APIView中去查询。没有我们再去它的爷爷类 View

def handle_exception(self, exc):
	"""
	Handle any exception that occurs, by returning an appropriate response,
	or re-raising the error.
	"""
	#做一个类型的判断,看看是否是因为没有认证或者是因为认证失败产生的异常
	if isinstance(exc, (exceptions.NotAuthenticated,
						exceptions.AuthenticationFailed)):
		# WWW-Authenticate header for 401 responses, else coerce to 403
		auth_header = self.get_authenticate_header(self.request)

		if auth_header:
			exc.auth_header = auth_header
		else:
			exc.status_code = status.HTTP_403_FORBIDDEN
	
	#判断之后,便会执行这句话,我们可以根据这个  get_exception_handler 方法继续查看
	#获取异常处理的方法
	exception_handler = self.get_exception_handler()
	context = self.get_exception_handler_context()
	
	#异常处理的结果
	response = exception_handler(exc, context)
	
	#如果不是以上捕捉的异常,则会按照restframework中自定义的处理,所以我们要处理的也是这个
	if response is None:
		self.raise_uncaught_exception(exc)

	response.exception = True
	return response

get_exception_handler()

def get_exception_handler(self):
	"""
	Returns the exception handler that this view uses.
	"""
	return self.settings.EXCEPTION_HANDLER

这个返回的就是全局配置,此时的 selfviews,所以我们可以进入到 rest_framework 中的 setting.py 去查找这个字段

#这个里面我们,可以找到它的配置路径,所以,我们可以通过该配置路径,实现自定义的exception_handler
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
'NON_FIELD_ERRORS_KEY': 'non_field_errors',

restframework/views.py找到 exception_handler的方法

def exception_handler(exc, context):
    """
    Returns the response that should be used for any given exception.

    By default we handle the REST framework `APIException`, and also
    Django's built-in `Http404` and `PermissionDenied` exceptions.

    Any unhandled exceptions may return `None`, which will cause a 500 error
    to be raised.
    """
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()

    if isinstance(exc, exceptions.APIException):
        headers = {}
        if getattr(exc, 'auth_header', None):
            headers['WWW-Authenticate'] = exc.auth_header
        if getattr(exc, 'wait', None):
            headers['Retry-After'] = '%d' % exc.wait

        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}

        set_rollback()
        return Response(data, status=exc.status_code, headers=headers)

    return None

exc就是具体的报错信息

context`就是初始化了下面的参数,所以通过字典的取值可以查看详细的参数。

def get_exception_handler_context(self):
        """
        Returns a dict that is passed through to EXCEPTION_HANDLER,
        as the `context` argument.
        """
        return {
            'view': self,
            'args': getattr(self, 'args', ()),
            'kwargs': getattr(self, 'kwargs', {}),
            'request': getattr(self, 'request', None)
        }

以上就是一场模块的流程,可以通过 pycharm中的断点调试,一步步的进行理解。

有了这个模块,那没有处理的异常,就会得到处理,让前端得到合理的异常信息。

好啦,今天就到这了,理解尚浅,不断查看源码,希望会有更深的理解,加油!

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42992704/article/details/105381614
今日推荐