基于django中的restful framework框架下的APIView源码分析

CBV源代码执行流程分析

我们知道CBV中,访问路由的时候,会先执行View中的dispatch()方法。
那么APIView是如何执行的呢?
我们依然从url.py文件配置入手分析

path('api/v1/auth/',AuthView.as_view()),

ctrl+鼠标左键,点击 as_view() 看看程序是如何执行的。
注意:点进去之后,进入的是rest_framework下的view.py文件,不再是base.py文件了。
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(APIView, cls).as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)

APIView点进去看看,发现class APIView(View):
原来APIView类是继承View类,view类正是from django.views import View下的View。

关键的代码:
view = super(APIView, cls).as_view(**initkwargs)
调用了父类View中的as_view方法,

上篇CBV源码分析中我们知道,当as_view执行后,当浏览器访问某个api接口时候, 就会先触发dispatch
然而API方法中也有自己的dispatch方法,所以会执行自己的方法,而不是去执行父类的dispatch方法,以下是代码

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)
    self.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

关键的代码:

request=self.initialize_request(request, *args, **kwargs)

点initialize_request进去看看,从字面意思就是对请求来的request,进行再次封装,初始化request,跟进代码

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
        )

initialize_request()实现的功能:将django原始的WSGIRequest,进行了改造,重新返回的是rest_framework.request.Request对象。
我们来看下初始化好的,经过处理后的Request类里面的代码参数。
parsers=self.get_parsers() 是获取解析器(用来解析通过get_parser_context构造的字典数据的)
parser_context=parser_context是构造好的原生request封装的字典格式数据
negotiator=self.get_content_negotiator() 一个内容协商类,它决定如何为响应选择一个呈现器,给定一个传入请求 。
关键点 authenticators=self.get_authenticators()
get_authenticators()实现的功能:获取[auth() for auth in self.authentication_classes]认证列表,里面是存放的一个个认证类对象。

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [auth() for auth in self.authentication_classes]

再根据authentication_classes,代码定位到:

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

根据 api_settings,定位到:

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

再根据DEFAULTS,定位到

'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication'
    )

我们通过from rest_framework.authentication import BasicAuthentication来简单看下 。
BasicAuthentication的父类BaseAuthentication的代码如下,里面有2个方法,也就是进行认证,我们可以利用此来扩充校验认证规则

class BaseAuthentication(object):
    def authenticate(self, request):
        raise NotImplementedError(".authenticate() must be overridden.")
    def authenticate_header(self, request):
        pass

get_authenticators方法就是去遍历继承类SessionAuthentication、BasicAuthentication的子类的列表,里面是一个一个子类对象,因为在列表推导式中[auth() for auth in self.authentication_classes]通过auth()获取类的实例对象。
咱们可以在views.py文件中自定义认证类,进行局部配置。

class LoginView(APIView):
    authentication_classes = [MyAuthentication]

get_authenticators会从自身找寻,如果查询不到,再去全局配置中查找。

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

点initial进去看看

def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        #Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        #Determine the API version, if versioning is in use.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        #Ensure that the incoming request is permitted
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)

完善request请求的一些注意事项,例如用户认证、权限认证、访问频率控制 。
我们先看perform_authentication看看内部到底是如何进行用户认证的?

 def perform_authentication(self, request):
        request.user

perform_authentication方法中只有一行代码request.user,这个用法是利用了properyt特性,通过属性转换为方法,这是python标准库的语法,那好,我们去request中去搜索带有property语法糖的user属性,去哪里搜呢?还记得我们django自己封装的那个Request嘛?

 @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

上来就判断not hasattr(self, ‘_user’):如果request首次没有进行request.user=XXX赋值操作,所以会进行如下操作

        with wrap_attributeerrors():
            self._authenticate()              

我们直接看self._authenticate()方法吧

def _authenticate(self):
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return
    self._not_authenticated()

代码意思是循环遍历那些认证对象列表,进行authenticator.authenticate(self)认证
方法如下:

class ForcedAuthentication(object):
    def __init__(self, force_user, force_token):
        self.force_user = force_user
        self.force_token = force_token
    def authenticate(self, request):
        return (self.force_user, self.force_token)

ForcedAuthentication这个是哪里来的呢?我们在最初构建自身的Request对象时候,在初始化__init__方法中通过用户和Token方式

forced_auth = ForcedAuthentication(force_user, force_token)
self.authenticators = (forced_auth,)

进行封装forced_auth类操作,再次赋值,也就是ForcedAuthentication类,通过如下类方法

 def authenticate(self, request):
        return (self.force_user, self.force_token)

进行用户认证校验,返回一个元组数据格式
我们继续回过头来看_authenticate方法,为了方便查看,我在此贴出此类代码

def _authenticate(self):
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

    self._not_authenticated()

当user_auth_tuple = authenticator.authenticate(self)认证校验过程中出现异常,
会抛出如下异常

def _not_authenticated(self):
    """
    Set authenticator, user & authtoken representing an unauthenticated request.

    Defaults are None, AnonymousUser & None.
    """
    self._authenticator = None

    if api_settings.UNAUTHENTICATED_USER:
        self.user = api_settings.UNAUTHENTICATED_USER()
    else:
        self.user = None

    if api_settings.UNAUTHENTICATED_TOKEN:
        self.auth = api_settings.UNAUTHENTICATED_TOKEN()
    else:
        self.auth = None

我们来看下,它是在settings.py 进行定义,它位于rest-framework模块下,这个settings.py不是项目根目录下的settings.py哦

'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser'
'UNAUTHENTICATED_TOKEN': None,

最后在_authenticate方法中,接着执行如下代码:

if user_auth_tuple is not None:
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

就为django rest-framework封装的Request示例,赋值添加属性self.user, self.auth即可,执行操作完毕返回,如果有异常,raise方法self._not_authenticated(),在_authenticate方法末尾去执行_not_authenticated方法,也就是上面提到的异常代码

至此如下的用户认证、权限认证、访问频率,已经处理完毕用户认证


response = handler(request, *args, **kwargs)这里面是执行了对应的请求操作,如get\post请求,也就是执行了我们自定义视图里面的get方法等,在处理完毕后,赋值response然后作为参数进行如下的操作

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

看一下finalize_response实现什么功能?

    def finalize_response(self, request, response, *args, **kwargs):
        """
        Returns the final response object.
        """
        # Make the error obvious if a proper response is not returned
        assert isinstance(response, HttpResponseBase), (
            'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
            'to be returned from the view, but received a `%s`'
            % type(response)
        )

        if isinstance(response, Response):
            if not getattr(request, 'accepted_renderer', None):
                neg = self.perform_content_negotiation(request, force=True)
                request.accepted_renderer, request.accepted_media_type = neg

            response.accepted_renderer = request.accepted_renderer
            response.accepted_media_type = request.accepted_media_type
            response.renderer_context = self.get_renderer_context()

        # Add new vary headers to the response instead of overwriting.
        vary_headers = self.headers.pop('Vary', None)
        if vary_headers is not None:
            patch_vary_headers(response, cc_delim_re.split(vary_headers))

        for key, value in self.headers.items():
            response[key] = value

        return response

随后self.response = self.finalize_response(request, response, *args, **kwargs)返回,这一步操作,跟它的父类View是不同的,
在继承APIView的视图中,get\post需要返回HttpResponse,然后再通过self.finalize_response进一步封装,最后返回。

继承APIView的编写的视图,在views.py文件中:

class BookView(APIView):
    def get(self,request,*args,**kwargs):
        book_list = Book.objects.all()
        #当我们输入参数many = True时, serializer还能序列化queryset
        bs = BookSerializers(book_list, many=True)
        #print(bs.data)  # 序列化的结果
        return Response(bs.data)

你可能感兴趣的:(思路分析)