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

 

posted @ 2018-12-06 20:46  Montant  阅读(440)  评论(0编辑  收藏  举报