zoukankan      html  css  js  c++  java
  • CBV和APIView流程

        restframework安装   

    1.下载pip install djangorestframework
    2.使用时:在INSTALLED_APPS加入"rest_framework"
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        "rest_framework"
    ]
    
    

    restful协议

    url
    一切皆资源
    book / add
    books
    book / 1 / change
    book / 1 / delete
    在restful中:
    books - ------get  :查询所有书籍 - ------- 返回的查询的所有书籍
    books - ------post :添加一本书籍 - ------- 返回添加书籍
    books / 1 - ------get :查看某本书籍 - ------- 返回这本书籍
    books / 1 - ------put / patch :编辑某本书籍 - ---返回编辑后的书籍
    books / 1 - ------delete :删除某本书籍 - ---返回空

            CBV流程解析     

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^book/', views.BookView.as_view()),
        url(r'^book/(d+)', views.BookDetailView.as_view()),
    ]

    请求走到url中,怎么执行的?

    1.执行View中的as_view,返回结果view 
    2.执行View中的view,返回结果self.dispatch,self为自定义的类的对象,自定义类中无dispatch方法
    就执行View中的dispatch
    3.执行View中的dispatch,利用反射执行对应的请求函数
    class BookView(View):
        def get(self,request):
            return HttpResponse("get.........")
        def post(self,request):
            return HttpResponse("post........")
    1.请求找到 url(r'^book/', views.BookView.as_view())这条路由,执行views.BookView.as_view()
    views.BookView是我们在views中自定义的类,在这里调用了as_view,那么as_view应该是类中的属性或方法,
    而自定义的类中没有as_view,应该去其父类中查找
    去View中查找as_view,查看源码及进行分析
    
    
    class View(object):
     @classonlymethod
        def as_view(cls, **initkwargs):
            """
            Main entry point for a request-response process.
            """
            for key in initkwargs:
                if key in cls.http_method_names:
                    raise TypeError("You tried to pass in the %s method name as a "
                                    "keyword argument to %s(). Don't do that."
                                    % (key, cls.__name__))
                if not hasattr(cls, key):
                    raise TypeError("%s() received an invalid keyword %r. as_view "
                                    "only accepts arguments that are already "
                                    "attributes of the class." % (cls.__name__, key))
    
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
    
            # take name and docstring from class
            update_wrapper(view, cls, updated=())
            # and possible attributes set by decorators
            # like csrf_exempt from dispatch
            update_wrapper(view, cls.dispatch, assigned=())
            return view
    View Code
    as_view是类方法,views.BookView.as_view()的结果是view
    url(r'^book/', views.BookView.as_view()),相当于 url(r'^book/', view) 根据函数式路由猜测views应返回一个函数名
    url(r'^book/', view) 一旦用户访问book 执行的是view(request),view返回了什么,在页面上就应该显示什么
    2.执行View中的view:
    view的源码
    def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
    view的执行结果是return self.dispatch(request),self是BookView的对象,去找dispatch方法,如果未定义,就去找父类View中的dispatch
    3.View中的dispatch
    def dispatch(self, request, *args, **kwargs):
            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
            return handler(request, *args, **kwargs)
    所有的请求方式:http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    当前请求在请求方式中的话,就利用反射调用请求方法
    url(r'^books/', view), # 一旦用户访问books 执行的是view(request)======self.dispatch(request)========self.get(request)

    1.BookView中无dispatch,执行View中的dispatch
    如果是get/post请求,就执行BookView中的get/post

    class BookView(View):
        def get(self,request):
            return HttpResponse("get.........")
        def post(self,request):
            return HttpResponse("post........")

    2.BookView中有dispatch,则不再执行View中的dispatch

     

    class BookView(View):
        def dispatch(self, request, *args, **kwargs):
            print("dispatch......")
        def get(self,request):
            return HttpResponse("get.........")
        def post(self,request):
            return HttpResponse("post........")

     

    无论是post还是get请求,均不会执行BookView中的get/post方法。因为BookView中有dispatch则不会执行
    View中的dispatch。在BookView中dispatch没设置返回值,页面会报错,在服务器后端显示dispatch.......

     

    3.即执行BookView中的dispatch又执行Views中的dispatch

     

    class BookView(View):
        def dispatch(self, request, *args, **kwargs):
            print("dispatch.......")
            ret=super().dispatch(request, *args, **kwargs)
            return  ret
        def get(self,request):
            return HttpResponse("get.........")
        def post(self,request):
            return HttpResponse("post........")

     

    好处:可以添加额外的功能

            APIview流程      

    1.执行APIView中的as_view,返回的结果super(APIView, cls).as_view(**initkwargs)
    2.执行View中的as_view,返回结果view
    3.执行View中的view,返回结果self.dispatch,self为自定义的类的对象,自定义类中无dispatch方法
    就执行APIview中的dispatch
    4.执行APIview中的dispatch,利用反射执行对应得请求函数,同时将原生得request进行封装

     

    1.在url中设计两条路由:

    url(r'^book/', views.BookView.as_view()),
    url(r'^book/(d+)', views.BookDetailView.as_view()),
    url(r'^book/', views.BookView.as_view())完成查询所有书籍和添加书籍的操作
    url(r'^book/(d+)', views.BookDetailView.as_view())完成查看某本书籍,编辑某本书籍和删除某本书籍的操作

    2.使用APIView

    from rest_framework.views import APIView
    class BookView(APIView):
        def get(self,request):
            book_obj=models.Book.objects.all()
            #将每个对象都取出来,放到列表中,序列化后返回
            temp=[]
            for obj in book_obj:
                temp.append({
                    "pk":obj.pk,
                    "title":obj.title
                })
            return HttpResponse(json.dumps(temp))
        def post(self,request):
            return HttpResponse("post........")
    1.在执行url时,执行views.BookView.as_view(), BookView中无as_view
    去父类APIView中查找
    class APIView(View):
        @classmethod
        def as_view(cls, **initkwargs):
             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
            view = super(APIView, cls).as_view(**initkwargs)
            view.cls = cls
            view.initkwargs = initkwargs
            return csrf_exempt(view)
    views.BookView.as_view()的结果是view,查看view
    2. view的值是View中as_view的返回值
    view = super(APIView, cls).as_view(**initkwargs)
    执行APIView父类View中as_view方法:
    class View(object):
        @classmethod
        def as_view(cls, **initkwargs):
          def as_view(cls, **initkwargs):
            pass
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
                self.request = request
                self.args = args
                self.kwargs = kwargs
                return self.dispatch(request, *args, **kwargs)
            view.view_class = cls
            view.view_initkwargs = initkwargs
            return view
    3.执行View中的view方法,结果执行self.dispatch(request, *args, **kwargs),
    BookView无dispatch方法,执行APIView中的dispatch方法
    4. 执行APIView中的dispatch方法
    class APIView(View):
    def dispatch(self, request, *args, **kwargs):
         self.args = args
            self.kwargs = kwargs
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
            try:
                self.initial(request, *args, **kwargs)
    
                # Get the appropriate handler method
                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)
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response
    try中的代码和View中dispatch的代码相同,均是利用反射执行对应的请求函数
    class View(object):
        def dispatch(self, request, *args, **kwargs):
            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
            return handler(request, *args, **kwargs)
    View Code
    
    
    5.封装APIView中dispatch方法中的request
    但两者的request是不同的,View中dispatch的request是原生的request
    而APIView中的dispatch方法中后续使用的request是封装过的request
    def dispatch(self, request, *args, **kwargs):
         request = self.initialize_request(request, *args, **kwargs)
         self.request = request
    在dispatch中,将原生的request作为initialize_request方法中的参数,执行后返回一个Request对象,将封装后的这个对象赋给request
    之后使用的request都是封装后的request
    def initialize_request(self, request, *args, **kwargs):
        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这个类:
    class Request(object):
            self._request = request
            self.parsers = parsers or ()
            self.authenticators = authenticators or ()
            self.negotiator = negotiator or self._default_negotiator()
            self.parser_context = parser_context
            self._data = Empty
            @property
            def query_params(self):
                return self._request.GET
    其中的_request属性的值就是原生的类,可通过调用这个属性来查看原生类的值
    
    

    1.在发送get时,打印接收值

    from rest_framework.views import APIView
    class BookView(APIView):
        def get(self,request):
            print(request.GET)
            print(request._request.GET)
            print(request.query_params)
            return HttpResponse("ok"<QueryDict: {'title': ['go']}>
    <QueryDict: {'title': ['go']}>
    <QueryDict: {'title': ['go']}>
    query_params和_request.GET是一样的

    2.使用post请求

    使用post请求时,原生的request只能解析urlencode数据使用封装后的request.data有着多种解析器
    使用urlencoded解析:
    def post(self,request):
        print("request.Post:",request.POST)
        print("request.data:", request.data)
         #获取值:
        print("request.data:", request.data["title"])
        return HttpResponse("post........")
    request.Post: <QueryDict: {'title': ['c++']}>
    request.data: <QueryDict: {'title': ['c++']}>


    其它解析:
    request.Post: <QueryDict: {}>
    request.data: {'title': 'c++'}
    request.data: c++

     

  • 相关阅读:
    让程序调用运行linux shell命令
    纯C的字符串问题
    Linux的打包和解压缩命令
    ubuntu安装mosquitto-1.4.5
    无Teamview授权,使用Teamview方式
    有效利用家用宽带,动态域名服务(DDNS)
    pfx格式证书转成nginx可用的证书
    iis文件上传限制
    vue脚手架使用
    netcore中执行linux命令
  • 原文地址:https://www.cnblogs.com/zgf-666/p/9199712.html
Copyright © 2011-2022 走看看