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++

 

原文地址:https://www.cnblogs.com/zgf-666/p/9199712.html