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中的断点调试,一步步的进行理解。

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

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

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是基于Djangorest_framework框架的ModelViewSet视图的源码解析: 1.基本介绍 ModelViewSet视图是Django框架的rest_framework模块中的一个视图类,它继承了GenericAPIView和Mixins,提供了对资源的CRUD操作。ModelViewSet视图类中提供了一系列的方法,如list、create、retrieve、update、partial_update、destroy等,这些方法对应着HTTP请求中的GET、POST、PUT、PATCH、DELETE等动词。 2.源码解析 ModelViewSet视图的源码主要涉及到以下几个部分: (1)视图类的定义 ``` class ModelViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, GenericViewSet): """ A viewset that provides default `create()`, `retrieve()`, `update()`, `partial_update()`, `destroy()` and `list()` actions. """ pass ``` 从源码可以看出,ModelViewSet继承了CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin和ListModelMixin这些视图混合类,以及GenericViewSet类。 (2)视图方法的实现 a. list方法 ``` def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) ``` list方法用于返回资源列表,它首先通过get_queryset方法获取查询集,然后通过filter_queryset方法对查询集进行过滤,最后通过get_serializer方法将查询集序列化为JSON数据返回给客户端。 b. create方法 ``` def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) ``` create方法用于创建资源,它首先通过get_serializer方法获取序列化器,然后通过perform_create方法进行资源的创建,最后返回HTTP 201 Created状态码以及资源的JSON数据。 c. retrieve方法 ``` def retrieve(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance) return Response(serializer.data) ``` retrieve方法用于获取单个资源,它通过get_object方法获取资源实例,然后通过get_serializer方法将资源实例序列化为JSON数据返回给客户端。 d. update方法 ``` def update(self, request, *args, **kwargs): partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) serializer.is_valid(raise_exception=True) self.perform_update(serializer) return Response(serializer.data) ``` update方法用于更新资源,它首先通过get_object方法获取资源实例,然后通过get_serializer方法获取序列化器,最后通过perform_update方法进行资源的更新,最终返回更新后的资源JSON数据。 e. partial_update方法 ``` def partial_update(self, request, *args, **kwargs): kwargs['partial'] = True return self.update(request, *args, **kwargs) ``` partial_update方法用于部分更新资源,它通过调用update方法,并将partial参数设置为True,进行资源的部分更新。 f. destroy方法 ``` def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) ``` destroy方法用于删除资源,它首先通过get_object方法获取资源实例,然后通过perform_destroy方法进行资源的删除,最终返回HTTP 204 No Content状态码。 3.总结 ModelViewSet视图是Django框架的rest_framework模块中的一个视图类,它继承了GenericAPIView和Mixins,提供了对资源的CRUD操作。通过对视图类的源码解析,我们可以深入了解ModelViewSet视图的内部实现,从而更好地理解和使用该视图类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值