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 (组件使用)

posted @ 2019-05-26 12:56  初遇ぃ  阅读(437)  评论(0编辑  收藏  举报
//一下两个链接最好自己保存下来,再上传到自己的博客园的“文件”选项中 //一下两个链接最好自己保存下来,再上传到自己的博客园的“文件”选项中