Django source --- APIView analysis of restfromwork

APIView analysis of Django's djangorestframework

as_view APIView class () method

First, we start from the view function, add a route in the URLconfig in urls.py

url(r'^books/',views.Book.as_view()),

At this point, we have not inherited from the BookView django.views in the View, but restframework.views in APIView

from django.shortcuts import render,HttpResponse
#导入APIView
from rest_framework.views import APIView

#继承自APIView
class Book(APIView):
    # 这里的request 是被封装后的request,原生的request在request._request
    # 如果想用原生request中的属性, 还是原来的用法,因为Request重写了__getattr__方法。
    # 原生django只能处理 urlencoded 和formdata编码。
    # 如果是json格式,原生django是不能处理的,需要自己从body中取出来自行处理。
    # request.data  不管前端传数据的格式是  urlencoded 和formdata编码 还是json 都从里面取值。
    # request.query_params  里面存的是原生Django 中 GET 方法提供的值
    
    # self.FILES  就是上传的文件
    def get(self,request):
        data = request.data
        
        print(data)
        return HttpResponse('get....')

    def post(self,request):
        return HttpResponse('post....')

as_view (): As the BookView not implemented as_view () method, when django start, as_view call () is APIView in as_view ()

as_view () method

# APIView 类中的 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.  
        这允许我们在进行URL反向查找时发现关于视图的信息
        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
        # APIView 是继承自django.views中的View,因此这里的 as_view() 也是调用父类的as_view()
        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)

Source analysis:

After inherited APIView:

  • All of the requests are not certified csrf
  • In essence APIView in as_view or call the parent class (View) in as_view ()
  • Call dispatch ---- as_view in> the dispatch of dispatch is APIView

dispatch () method

  • The request object made of native wrapper layer (object-oriented package), then after the request object is a new request object
  • In the APIView self.initial (request, * args, ** kwargs) which has a frequency control, access control and authentication-related
  • We write the corresponding method of the view class of the method performed according to a request:
    • view request object class methods, has become the encapsulated request
    • In the Request class:
      • Native request is self._request
      • Taken submit data in the form of post taken from the reuqest.data
      • query_params is a native of GET request data
      • When upload files taken from the FILES
      • (Important) Other property, own request. Attribute name (because rewrite the __getattr__ method)
# dispatch
def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,  该方法很想Django 原先的dispatch方法
        but with extra hooks for startup, finalize, and exception handling. 但是它扩展了一些用于启动,结束,异常处理的钩子
        """
        self.args = args  # 这里的self 对于上述的Book类而言是一个Book类的对象
        self.kwargs = kwargs
        # 将原先的request 封装后返回
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request  # 将 上面返回的值在request接收后,又放在self对象的自己的request中去
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 该处用的request 就是被封装过后的request,原先的request 在 rerquest._request中
            self.initial(request, *args, **kwargs)
            
            # Get the appropriate handler method
            # 如果request请求方法在在 http_method_names列表中的方法中
            if request.method.lower() in self.http_method_names:
                # getattr 反射去获取该方法的内存地址
                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

initialize_request() 方法

 def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        返回一个初始化的request对象
        """
        parser_context = self.get_parser_context(request)
        # 这个 return 的Request 类不是Django自己的request了, 是drf框架里面自己定义的Request
        # 把原生django的request对象封装到该Request对象中,并且叫 _reuqest
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

initial () method

    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)  # 频率

Reuqest class

class Request(object):

    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        ...
        #将原始的WSGIReqeust对象复制给_request
        self._request = request

        ....

    #调用旧的request.GET
    @property
    def query_params(self):return self._request.GET
    
    #调用旧的request.POST
    @property
    def POST(self):return QueryDict('', encoding=self._request._encoding)  
NOTE: request after use, objects are encapsulated restfromwork Request

Implementation process

"""
1.views.Book.as_view()
2.Book类中没有 as_view方法,去其父类APIView中找
3.在APIView中的as_view 方法中 执行了这样一句代码
    view = super(APIView, cls).as_view(**initkwargs)
    因此最终的as_view 还是从View 中的as_view来
4. 执行View里面的as_view()方法,返回view函数
5. url和视图函数之间建立绑定关系完毕,等待用户请求
6. 接收到用户请求,执行 Book--as_view(此处的as_view出处已再说上面,再次不再赘述)--View.as_view
7.执行self.dispatch()的时候,执行结果是什么就返回什么
8.开始找dispatch方法,self里面没有,Book类中也没有,在 APIView 中
9.开始执行APIView 中的 dispatch方法
10.最后找到http方法(get,post,put,delete)
11. 开始执行找到的方法(GET),self.get(),此时的self代表Book的实例化对象
12. 假设 请求为POST 请求,
    request.data  --->获取POST请求前端发送过来的数据
    request.FILES ----> 获取POST请求前端发送过来的文件
13. 开始执行reqeust.data
      @property
        def data(self):
            if not _hasattr(self, '_full_data'):
                self._load_data_and_files()
            return self._full_data
14. 执行该函数里面的  self._load_data_files()
15. 执行 self._load  self.files=self.parse()
16. 执行 parser = self.negotiator.select_parser(self, self.parsers)
17. 查找:self.parsers
18. 执行 并向上返回结果
"""

Guess you like

Origin www.cnblogs.com/qianzhengkai/p/11116691.html