zoukankan      html  css  js  c++  java
  • REST framework (组件源码流程分析)


    阅读目录

    一、APIView & View

    二、组件源码流程


    一、APIView & View

    • View
      • 路径:django.views.View
      • 使用:
        • urls: path('xxx/', views.xxxx.as_view(), name='xxx')
        • 视图:class xxxx(View):
    • ApiView
      • 路径:from rest_framework.views import APIView
      • 使用:
        • urls: path('xxx/', views.xxAPI.as_view(), name='xxx')
        • 视图:class xxAPI(APIView):
      • APIView继承View,重写as_view(),增加扩展配置

     

    二、组件源码流程分析 

    1. APIView源码分析

        1.路由:url(r'^books/$', views.BookView.as_view(),name="books") #  View下的view
    
        2.请求:books/一旦被访问 执行APIView.as_view() -> APIView: dispatch()
                     view = super(APIView, cls).as_view(**initkwargs)
    
        3.def dispatch():      # APIView
            # request加工
            request = self.initialize_request(request, *args, **kwargs) 
            
                      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
                            )
            
            # 构建request对象
            self.request=Request(request)
                         class Request(object):
                          self._request = request  # 原request
                          def query_params(self):
                             return self._request.GET
                          def data(self):
                             return post.data # post请求数据
    
           self.request._request
           self.request.GET  # get
           self.request.data # POST  PUT
            
           # 初始化组件信息
           self.initial(request, *args, **kwargs)
      
           分发----if get请求:
           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) # 视图: self.get(request, *args, **kwargs)               
           return response
    
        4.csrf_exempt(view)   #排除csrf

    1.1 APIView().initial() 流程

    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        # 1.确定请求是否包含“.json”样式格式后缀
        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)
    
            def perform_content_negotiation(self, request, force=False):
                """
                Determine which renderer and media type to use render the response.
                """
                # 2.渲染器
                renderers = self.get_renderers()   # [renderer() for renderer in self.renderer_classes]
                # 3.协商类
                conneg = self.get_content_negotiator()
                # if not getattr(self, '_negotiator', None):
                #      self._negotiator = self.content_negotiation_class()
                # return self._negotiator
    
                try:
                    # 选择渲染器
                    return conneg.select_renderer(request, renderers, self.format_kwarg)
                except Exception:
                    if force:
                        return (renderers[0], renderers[0].media_type)
                    raise
        # 调用request对象__setattr__赋值
        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)
            def determine_version(self, request, *args, **kwargs):
                """
                If versioning is being used, then determine any API version for the
                incoming request. Returns a two-tuple of (version, versioning_scheme)
                """
                if self.versioning_class is None:
                    return (None, None)
                # 4.version组件
                scheme = self.versioning_class() # api_settings.DEFAULT_VERSIONING_CLASS
                return (scheme.determine_version(request, *args, **kwargs), scheme
        # 调用request对象__setattr__赋值
        request.version, request.versioning_scheme = version, scheme

    # Ensure that the incoming request is permitted # 5.认证组件 self.perform_authentication(request) # 默认执行 def perform_authentication(self, request): request.user #执行request的user,这是的request已经是加工后的request了
          @property
          def user(self):
              """
              Returns the user associated with the current request, as authenticated
              by the authentication classes provided to the request.
              """
              if not hasattr(self, '_user'):
                  with wrap_attributeerrors():
                      self._authenticate()  #
              return self._user  #返回user

        # 执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
        def _authenticate(self):
              """
              Attempt to authenticate the request using each authentication instance
              in turn.
              """
              #循环对象列表
              for authenticator in self.authenticators:
                  try:
                      #执行每一个对象的authenticate 方法
                      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  #返回一个元组,user,和auth,赋给了self,
                      # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了
                      return
              self._not_authenticated() 

         # 如果没有认证成功
         def _not_authenticated(self):
              """
              Set authenticator, user & authtoken representing an unauthenticated request.
              Defaults are None, AnonymousUser & None.
              """
              #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置
              self._authenticator = None  #
              if api_settings.UNAUTHENTICATED_USER:
                  self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser
              else:
                  self.user = None  # None 表示跳过该认证
              if api_settings.UNAUTHENTICATED_TOKEN:
                  self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默认值为:None
              else:
                  self.auth = None
            # (user, token)
            # 表示验证通过并设置用户名和Token;
            # AuthenticationFailed异常
    
    
      # 6.权限组件
      self.check_permissions(request)
    def check_permissions(self, request):
    """
    Check if the request should be permitted.
    Raises an appropriate exception if the request is not permitted.
    """
    for permission in self.get_permissions():
    if not permission.has_permission(request, self):
    self.permission_denied(
    request, message=getattr(permission, 'message', None)
    )
    #if request.authenticators and not request.successful_authenticator:
    # raise exceptions.NotAuthenticated()
    # raise exceptions.PermissionDenied(detail=message)
      # 7.频率组件
      self.check_throttles(request)
    def check_throttles(self, request):
    """
    Check if request should be throttled.
    Raises an appropriate exception if the request is throttled.
    """
    for throttle in self.get_throttles():
    if not throttle.allow_request(request, self):
    self.throttled(request, throttle.wait()) # exceptions.Throttled(wait)
     

    APIView().dispatch()  执行结束分发至视图,紧接着执行视图中的 def get(request, *args, **kwargs) ,def post(request, *args, **kwargs) 等

    2. 视图执行流程

    操作数据:以Book表为例
        class BookView(APIView):
            # 查看所有书籍
            def get(self,request):
                book_list=Book.objects.all()
                bs=BookModelSerializers(book_list,many=True,context={'request': request})
                return Response(bs.data)
    
            # 添加一本书籍
            def post(self,request):
                # post请求的数据
                bs=BookModelSerializers(data=request.data)
                if bs.is_valid():
                    print(bs.validated_data)
                    bs.save()# create方法
                    return Response(bs.data)
                else:
                    return Response(bs.errors)
        class BookDetailView(APIView):
            # 查看一本书籍
            def get(self,request,id):
    
                book=Book.objects.filter(pk=id).first()
                bs=BookModelSerializers(book,context={'request': request})
                return Response(bs.data)
            # 更新一本书籍
            def put(self,request,id):
                book=Book.objects.filter(pk=id).first()
                bs=BookModelSerializers(book,data=request.data)
                if bs.is_valid():
                    bs.save()
                    return Response(bs.data)
                else:
                    return Response(bs.errors)
            # 删除某一本书籍
            def delete(self,request,id):
                Book.objects.filter(pk=id).delete()
    
                return Response()
    操作数据:以Book表为例

    分析:获取所有书籍,执行get方法查询数据库,返回对象/queryset交给自定制序列化类,分页后Response返回给前端,这个过程中DRF组件体现:

    • 序列化组件  
    • 分页组件 
    • 渲染器 

    三、总结

    根据上面的分析,总结DRF包含的几大组件如下:

    请求进来:

    1. 路由(可自定制路由)
    2. 版本
    3. 认证
    4. 权限
    5. 频率
    6. 获取数据(解析器)请求头解析
    7. 序列化
    8. 分页
    9. 渲染器
    10. 视图   # DRF视图不只有APIView

     本文基于APIView源码流程分析总结DRF几大组件,组件的使用请见 REST framework (组件使用)

  • 相关阅读:
    手写DAO框架(六)-框架使用示例
    手写DAO框架(五)-DAO层实现
    堵车时如何快速行车
    win10如何安装mariadb
    工程开发中的“事务”
    通过网页或者移动设备链接跳转qq(tim)添加好友(群)
    通过网页或者移动设备链接跳转qq(tim)添加好友(群)
    蓝桥杯历届真题,算法学习讨论群(互相学习,多交流才能进步)
    项目的登录注册如何用邮箱发送验证码
    项目的登录注册如何用邮箱发送验证码
  • 原文地址:https://www.cnblogs.com/zhangliang91/p/10925706.html
Copyright © 2011-2022 走看看