zoukankan      html  css  js  c++  java
  • django的view.view和DRF的APIView的源码解析

    一.classbasedview的源码剖析

    1. 启动django:python manage.py runserver 127.0.0.1:8000
    2. 加载settings
      2.1 读取models.py
      2.2 views.py
      2.3 urls.py
        2.3.1 开始执行as_views(): views.LoginView.as_view(), 返回view函数
        2.3.2 此时url对应具体的某一个函数
      2.4 开始等待用户请求(127.0.0.1:8000/books/)
      2.5 开始执行view函数:view(request)

    urls.py

    from django.urls import path, include, re_path
    from classbasedview import views
    
    urlpatterns = [
        re_path('books/$', views.BookView.as_view()),
    ]

    viws.py

    from django.views import View
    
    class View:
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
        @classmethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                 # 实例化一个对象,对象名称为self,self是cls的对象,谁调用了cls
                 # cls就是谁(当前调用cls的是BookView),
                 # 所以,此时的self就是BookView的实例化对象
                 self = cls(**initkwargs)
                 if hasattr(self, 'get') and not hasattr(self, 'head'):
                      self.head = self.get
                 # 此时的request对象指向原始的request对象
                 # 给self这个实例化对象赋值:原始的request
                 self.request = request
                 self.args = args
                 self.kwargs = kwargs
                 # 开始执行self.dispatch()
                 return self.dispatch(request, *args, **kwargs)
                            
            return view
                            
         def dispatch(self, request, *args, **kwargs):
             if request.method.lower() in self.http_method_names:
                  # 通过getattr找到的属性,已经和对象绑定了,访问的时候不需要在指明对象了
                  # 不需要再:self.handler
                  # 直接handler()
                  handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
              else:
                 handler = self.http_method_not_allowed
              return handler(request, *args, **kwargs)
    
    class BookView(View):
        def get(self, request):
            pass
                        
        def post(self, request):
            pass

    二.DRF的APIView的请求流程和源码剖析

      本质上DRF是django的一个app(startproject)

      flask:flask-REST

      封装了很多功能

        - APIView(所有的功能都是基于APIView的)

        - 解析器组件
        - 序列化组件
        - 认证组件
        - 权限组件
        - 视图组件

    1.使用方法

    1. 导入模块
        views.py
    
        from rest_framework.views import APIView
                        
    2. 继承APIView
          class BookView(APIView):
               def get(self, request):
                    pass
                                
              def post(self, request):
                    pass
                        
    3. urls.py
          from django.urls import path, include, re_path
          from classbasedview import views
    
          urlpatterns = [
                re_path('login/$', views.LoginView.as_view()),
          ]

    2.源码解析

      1. 启动django:Python manage.py runserver 127.0.0.1:8000
      2. 加载settings:
        2.1 加载models.py
        2.2 加载views.py
        2.3 加载urls.py
          2.3.1 re_path('BookView/$', views.BookView.as_view()), 开始执行as_view()方法
          2.3.2 urls.py加载完毕,url和视图函数之间的绑定关系已经建立好了
        3. 等待用户请求
        4. 接收到用户请求:127.0.0.0:8000/books/
        5. 开始查找url和视图函数之间的绑定关系,根据用户请求的url找到对应的视图函数
        6. 开始执行视图函数view(request)
        7. 开始执行self.dispatch()
        8. 将view函数的返回结果返回给客户端浏览器

    class View:
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
        def __init__(self, **kwargs):
    
             for key, value in kwargs.items():
                 setattr(self, key, value)
    
         @classonlymethod
         def as_view(cls, **initkwargs):
             def view(request, *args, **kwargs):
                  # 实例化一个对象,BookView的实例对象
                  self = cls(**initkwargs)
                  # self表示BookView的实例化对象
                  # 把原始的request请求对象赋值给self.request
                  self.request = request
                  self.args = args
                  self.kwargs = kwargs
                  # view函数的返回结果就是self.dispatch()
                  return self.dispatch(request, *args, **kwargs)
             # 此时的cls是BookView
             view.view_class = cls
             view.view_initkwargs = initkwargs
    
             return view
    
         class APIView(View):
              @classmethod
              def as_view(cls, **initkwargs):
                   # cls是BookView
    
                   view = super(APIView, cls).as_view(**initkwargs) # View:view
                   view.cls = cls
                   view.initkwargs = initkwargs
    
                   # 返回一个view函数
                   return csrf_exempt(view)
                        
               def dispatch(self, request, *args, **kwargs):
                   try:
                                
                      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)
    
                    return self.response
    
            class BookView(APIView):
                 def get(self, request):
                     pass
                            
                 def post(self, request):
                     pass

    三.DRF解析器的请求流程和源码剖析

    1.使用方法

    1. 导入模块
        views.py
    
        from rest_framework.views import APIView
                        
    2. 继承APIView
        class BookView(APIView):
             def get(self, request):
                  pass
                                
             def post(self, request):
                  pass
                        
    3. urls.py
         from django.urls import path, include, re_path
         from classbasedview import views
    
         urlpatterns = [
             re_path('login/$', views.LoginView.as_view()),
         ]
                        
    4. def post(self, request):
           origin_data = request.data
           ....
           return HttpResponse({})

    2.源码解析

      1. 启动django:Python manage.py runserver 127.0.0.1:8000
      2. 加载settings:
        2.1 加载models.py
        2.2 加载views.py
        2.3 加载urls.py
          2.3.1 re_path('BookView/$', views.BookView.as_view()), 开始执行as_view()方法
          2.3.2 urls.py加载完毕,url和视图函数之间的绑定关系已经建立好了
      3. 等待用户请求
      4. 接收到用户请求:127.0.0.0:8000/books/ POST
      5. 开始self.post()
        5.1 request.data触发解析操作
        5.2 获取返回值
      6. 将view函数的返回结果返回给客户端浏览器

    class View:
        http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    
        def __init__(self, **kwargs):
    
             for key, value in kwargs.items():
                  setattr(self, key, value)
    
        @classonlymethod
        def as_view(cls, **initkwargs):
             def view(request, *args, **kwargs):
                  # 实例化一个对象,BookView的实例对象
                  self = cls(**initkwargs)
                  # self表示BookView的实例化对象
                  # 把原始的request请求对象赋值给self.request
                  self.request = request
                  self.args = args
                  self.kwargs = kwargs
                  # view函数的返回结果就是self.dispatch()
                  return self.dispatch(request, *args, **kwargs)
              # 此时的cls是BookView
              view.view_class = cls
              view.view_initkwargs = initkwargs
    
              return view
                            
         class Request(object):
               def __init__(self, request, parsers=None, authenticators=None,
                       negotiator=None, parser_context=None):
                   elf._request = request
                    self.parsers = parsers or ()  # self.get_parsers()的执行结果
                            
                # 触发解析操作
                @property
                def data(self):
                     if not _hasattr(self, '_full_data'):
                          self._load_data_and_files()
                     return self._full_data
                            
                def _load_data_and_files(self):
                     """
                     Parses the request content into `self.data`.
                     """
                     if not _hasattr(self, '_data'):
                          # 开始执行self._parse()
                          self._data, self._files = self._parse()  # parsed_data
                          if self._files:
                               self._full_data = self._data.copy()
                               self._full_data.update(self._files)
                          else:
                               self._full_data = self._data
    
                          # if a form media type, copy data & files refs to the underlying
                          # http request so that closable objects are handled appropriately.
                          if is_form_media_type(self.content_type):
                              self._request._post = self.POST
                              self._request._files = self.FILES
                                    
                 def _parse(self):
                      """
                      Parse the request content, returning a two-tuple of (data, files)
    
                      May raise an `UnsupportedMediaType`, or `ParseError` exception.
                      """
                      media_type = self.content_type
    
                      parser = self.negotiator.select_parser(self, self.parsers)
    
                      if not parser:
                          raise exceptions.UnsupportedMediaType(media_type)
    
                      try:
                           parsed = parser.parse(stream, media_type, self.parser_context)
                      except Exception:
                                # If we get an exception during parsing, fill in empty data and
                                # re-raise.  Ensures we don't simply repeat the error when
                                # attempting to render the browsable renderer response, or when
                                # logging the request or similar.
                                self._data = QueryDict('', encoding=self._request._encoding)
                                self._files = MultiValueDict()
                                self._full_data = self._data
                                raise
    
                            # Parser classes may return the raw data, or a
                            # DataAndFiles object.  Unpack the result as required.
                            try:
                                return (parsed.data, parsed.files)
                            except AttributeError:
                                empty_files = MultiValueDict()
                                return (parsed, empty_files)
                                    
    
                    class APIView(View):
                        from rest_framework.settings import api_settings
    
                        parser_classes = api_settings.DEFAULT_PARSER_CLASSES
                        
                        @classmethod
                        def as_view(cls, **initkwargs):
                            # cls是BookView
    
                            view = super(APIView, cls).as_view(**initkwargs) # View:view
                            view.cls = cls
                            view.initkwargs = initkwargs
    
                            # 返回一个view函数
                            return csrf_exempt(view)
                        
                        def initialize_request(self, request, *args, **kwargs):
                            from rest_framework.request import Request
    
                            return Request(
                                request,
                                parsers=self.get_parsers(),
                            )
                            
                        def get_parsers(self):
                            # [<class 'rest_framework.parsers.JSONParser'>, 
                            # <class 'rest_framework.parsers.FormParser'>, 
                            # <class 'rest_framework.parsers.MultiPartParser'>]
                            return [parser() for parser in self.parser_classes]
                        
                        def dispatch(self, request, *args, **kwargs):
                            # 初始化request,将原来的request对象传递给初始化函数
                            request = self.initialize_request(request, *args, **kwargs)
                            self.request = request
                            try:
                                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)
    
                            return self.response
    
                    class BookView(APIView):
                        def get(self, request):
                            pass
                            
                        def post(self, request):
                            parsed_data = request.data

  • 相关阅读:
    python正则表达式(+ {})(二)
    14丨 HTTP有哪些优点?又有哪些缺点?
    python正则表达式(. *)(一)
    12丨响应状态码该怎么用?
    Fiddler—Fiddler+willow插件应用(十四)
    11丨你能写出正确的网址吗?
    【洛谷P1858】多人背包
    【洛谷P3387】(模板)缩点
    【洛谷P2184】贪婪大陆
    Leetcode: 39. Combination Sum
  • 原文地址:https://www.cnblogs.com/chenxi67/p/10079413.html
Copyright © 2011-2022 走看看