Python 学习笔记(十四)--Django REST Framework中ViewSets 与APIView

一. ViewSets

1.1 常见导入使用

from rest_framework.viewsets import ModelViewSet

 1.2 功能描述

"""
ViewSets are essentially just a type of class based view, that doesn't provide
any method handlers, such as `get()`, `post()`, etc... but instead has actions,
such as `list()`, `retrieve()`, `create()`, etc...

Actions are only bound to methods at the point of instantiating the views.

    user_list = UserViewSet.as_view({'get': 'list'})
    user_detail = UserViewSet.as_view({'get': 'retrieve'})

Typically, rather than instantiate views from viewsets directly, you'll
register the viewset with a router and let the URL conf be determined
automatically.

    router = DefaultRouter()
    router.register(r'users', UserViewSet, 'user')
    urlpatterns = router.urls
"""

 1.3 类的定义(继承关系)

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):

1.4  继承类 GenericViewSet的定义

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass

这个来自导入

from rest_framework import generics, views

二 进入generics  

继续看  generics 中的GenericAPIView

class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """
    # You'll need to either set these attributes,
    # or override `get_queryset()`/`get_serializer_class()`.
    # If you are overriding a view method, it is important that you call
    # `get_queryset()` instead of accessing the `queryset` property directly,
    # as `queryset` will get evaluated only once, and those results are cached
    # for all subsequent requests.

注意继承关系,来自于

from rest_framework import views

 三 继续views【rest_framework中的views】

"""
Provides an APIView class that is the base of all views in REST framework.
"""

class APIView(View):

    # The following policies may be set at either globally, or per-view.

View的继承就是django中原生的view了。

from django.views.generic import View

四.django中原生的view

源码位置;

 主要方法

    @classonlymethod  ##指明是类方法,通过类可以直接调用。会把类自动传入。
    def as_view(cls, **initkwargs):   ###把类cls自动传入;intikwargs 还可以接受其他参数 
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError(
                    'The method name %s is not accepted as a keyword argument '
                    'to %s().' % (key, cls.__name__)
                )
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs): ###request为当此请求的request对象。
            self = cls(**initkwargs)        ###实例化等到一个对象。对象---你自己之前定义的model,也就是传入的cls类型。
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)  ##request为当次请求的request
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view  ###注意,返回的是一个叫view的内层函数(或者说是内层函数的内存地址)。请求一旦来了,如果url匹配成功,会把当次请求的request对象,
###作为一个参数,传送给这个内层函数,来执行。

其中调用到的基础方法

    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        if hasattr(self, 'get') and not hasattr(self, 'head'):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

 

    def dispatch(self, request, *args, **kwargs): 
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
##request为当次请求的request
## 判断请求方式在不在允许的请求方式里 if request.method.lower() in self.http_method_names:
##handler映射为你定义的model中的那个方法(或叫作内存地址),例如自己定义的类中的get()方法。 handler
= getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) ###执行定义的方法。

 五. APIView中的源码分析

5.1 一般导入

from rest_framework.views import APIView

5.2 主要的方法可看本文第三部分的截图

5.3 方法as_view()

    @classmethod
    def as_view(cls, **initkwargs):  ##同样也是类的绑定方法
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    'Do not evaluate the `.queryset` attribute directly, '
                    'as the result will be cached and reused between requests. '
                    'Use `.all()` or call `.get_queryset()` instead.'
                )
            cls.queryset._fetch_all = force_evaluation

        view = super().as_view(**initkwargs)  ##调用父类(django的view)的as_view方法;
        view.cls = cls ##注意,python中一切皆对象;函数也是对象。是对象,就可以有属性,有值。
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt. ##以后所有的请求,都没有csrf认证了。【只要继承了APIVeiw,就没有crsf的认证了,而是运用了自己的自己的认证】
        return csrf_exempt(view) ##局部禁用csrf --- 还有已用用法:就是在视图函数上加装饰器@crsf_exempt

需要特别留意的是view中调用的dispatch()是APIView中的dispatch()方法。

【首先用户定义的类中去找-->找不到,再在APIView中去找】---说明: 请求来了-->匹配url-->view(request)--->self.dispatch() [注意self是APIView对象]

    # Note: Views are made CSRF exempt from within `as_view` as to prevent
    # accidental removal of this exemption in cases where `dispatch` needs to
    # be overridden.
    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
###请求模块(解析模块) request
= self.initialize_request(request, *args, **kwargs) ##参数中的request是当次请求的request对象;返回的是一个新的request对象,
##不在是django原生的request了,
##是drf自己定义的request。 self.request
= request ##赋值的是一个新的request对象 self.headers = self.default_response_headers # deprecate? 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 ###响应模块 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

请求模块(解析模块)调用的方法

    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
##准备要解析的数据
parser_context = self.get_parser_context(request) ##重新打包 return Request( request,
##获取解析类 parsers
=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context )

 

posted @ 2023-12-24 00:30  东山絮柳仔  阅读(196)  评论(0编辑  收藏  举报