cbv请求分析

CBV源码分析

DRF中中所有视图都是基于CBV形式完成, 所以分析其cbv源码, 了解drf的基本请求流程就比较有必要了.

urls.py
"""下面是一个通用的url路由""""
url(r'^books/$', views.Book.as_view())

"""as_view同样是drf视图类的入口"""
views.py
"""下面是一个通用的简单的基于drf的apiview的一个视图"""
class Book(APIView):
    def get(self, request, *args, **kwargs):
        # 这个接口提供两个接口来进行调用, 所以需要分开来进行判断
        # 判断路由中是否包含pk
        pk = kwargs.get('pk')
        # pk有值, 代表是查单本书
        if pk:
            try:
                book = models.Book.objects.get(pk=pk, is_delete=False)
            except models.Book.DoesNotExist:
                return Response({
                    'status': 1,
                    'msg': '图书不存在'
                })
            ser_data = serializers.BookModelSerializer(book).data
        # 当没有查询单本书时, 即pk不存在的话, 默认进行查询所有图书
        else:
            books = models.Book.objects.filter(is_delete=False)  # 要找没有被删除的书籍
            ser_data = serializers.BookModelSerializer(books, many=True).data  # 不要忘记添加many=True的条件, 序列化多个对象对象
        return Response({
            'status': 0,
            'msg': '查询成功',
            'result': ser_data
        })

as_view入口分析

首先drf的apiview是继承自django中View, 并重写了as_view方法, 也就相当于改写了入口方法.

	@classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
		# 直接禁用了csrf认证, 所以我们的post请求可以不携带csrftoken参数了.
        return csrf_exempt(view)

上面是APIView的as_view方法, 重写的内容很简单, 只是将csrf认证禁用了, 并进行了一些参数的初始化工作. 接下来是重点, as_view方法调用了父类的as_view方法, 返回的结果才是url匹配后真正执行的内容, 也就是调用了dispatch方法来分发.

dispatch分析

"""django的View的as_view方法"""
@classonlymethod
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            # 视图类调用的方法.
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs
        update_wrapper(view, cls, updated=())
        update_wrapper(view, cls.dispatch, assigned=())
        return view

上面的源码部分清晰的看出了, 最后我们的路由匹配成功后, 最后走的是as_view内层的view方法, 也就是说调用了view类的dispatch方法, 而APIView正式重写了这个dispatch方法, 在这里做了许多的事, 因此可以说, dispatch才是drf中APIView的真正入口函数.

    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 重新封装了request对象
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 这里做了各种初始化工作, 包括频率,认证, 权限等的校验.
            self.initial(request, *args, **kwargs)
            # 和django中的一样, 需要符合对应的8种http请求方法, 才能正确走到对应的视图函数进行处理.
            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
		   # 调用视图函数来处理具体的业务逻辑
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            # 自带的异常处理.
            response = self.handle_exception(exc)
		# 处理返回的响应
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
原文地址:https://www.cnblogs.com/yscl/p/11930762.html