欢迎来到氵一壶灬清酒い的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。

DRF(1) ------- APIView | 解析器组件

Django基于类的视图(CBV)执行流程

一,CBV基于类的视图

视图是可以调用的,它接受请求并返回响应,这不仅仅是一个函数,Django提供了一些可以用作视图的类的例子,这些允许通过继承或mixin来构建视图并重用代码.

基本实例

Django提供了基本的视图类,它将适用于广泛的应用程序.所有视图类都继承自View该类,它处理将视图连接到URL,HTTP方法调用其他简单的功能.

在URLconf中简单使用.

BookView是一个视图类,而不是一个函数,所以我们将URL指向as_view()类方法,它为基于类的视图提供了类似于函数的条目:

from django.urls import re_path
from serializer import views

urlpatterns = [
    re_path(r'books/$', views.BookView.as_view()),
]

Bookview类

继承现有的view并覆盖父类中的方法

 1 # 第一步,导入模块
 2 from rest_framework.views import APIView
 3 from rest_framework.response import Response
 4 
 5 from .models import (Book,Publish,Author,)
 6 from .app_serializers import BookSerializer
 7 # Create your views here.
 8 
 9 class BookView(APIView):
10     def get(self, request):
11         # 第三步,获取queryset
12         origin_data = Book.objects.all()
13 
14         # 第四步,开始序列化
15         serialized_data = BookSerializer(origin_data, many=True)
16 
17         return Response(serialized_data.data)
18 
19     def post(self, request):
20 
21         verified_data = BookSerializer(data=request.data)
22 
23         if verified_data.is_valid():
24             book = verified_data.save()
25             authors = Author.objects.filter(nid__in=request.data['authors'])
26             book.authors.add(*authors)
27             return Response(verified_data.data)
28         else:
29             return Response(verified_data.errors)

二, View

主要的基于类的基本视图,所有其他基于类的视图都是继承自这个View类,导入方式:

from django.views import View

浏览器向服务器发送get请求,基于视图类的执行流程:

首先是Django启动,会执行视图类下的as_view();

urlpatterns = [
    # as_view()  执行类的as_view()
re_path(r
'books/$', views.BookView.as_view()), ]

as_view():由于Bookview没有实现as_view()方法,会调用父类(View)中的as_view()方法.

@classonlymethod
    def as_view(cls, **initkwargs):
        """
        请求响应过程的主要入口点
        """
        ......
        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
            
            #view方法返回self.dispatch()方法的返回值
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs
        update_wrapper(view, cls, updated=())
        update_wrapper(view, cls.dispatch, assigned=())
        
        #返回view方法内存地址,当用户访问books/的时候,会调用改view()方法
        return view

self.dispatch():由于Bookview没有实现dispatch(),所以会调用View类的disoatch(),

主要作用:view视图的一部分-接受request参数和参数方法,并返回HTTP响应.

检测HTTP请求方法,并尝试委托给匹配HTTP方法的方法,一个GET将被委托给get(),POST委托给post() ...

def dispatch(self, request, *args, **kwargs):
    # 尝试把用户请求分发到正确的方法,如果方法不存在,遵从错误的处理程序
    # 如果请求方法不在已批准的列表中,也会遵从错误的处理程序
    if request.method.lower() in self.http_method_names:
        #使用反射,例如用户访问是get请求
        # handler = getattr(BookView,"get",错误处理程序)
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
        
    # return get(request,*args, **kwargs)
    return handler(request, *args, **kwargs)

Django Rest Framework----APIView执行流程

一,as_view()

首先,从URLconfig入手,由于BookView是一个机遇类的视图,所以将URL执行as_view()类方法.

 

re_path(r'books/$', views.BookView.as_view()),

 

此时的BookView已经不是继承自Django.view中的view了,而是restframework.view中的view.

BookView视图类:

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

#继承自APIView
class BookView(APIView):

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

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

as_view():由于BookView没有实现as_view()方法,Django启动时,调用的as_view()是APIview中的as_view()

@classmethod
def as_view(cls, **initkwargs):
    """
    将原始类存储在视图函数上
    这允许我们在执行url反向查找时发现有关视图的信息。
    """
    ...
    #由于APIView是继承自django.views中的View(上篇博客接触过)
    #调用父类(View)中的as_view()
    view = super(APIView, cls).as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs

    # 提示: 基于会话的身份验证被明确地CSRF验证
    # 所有其他身份验证都免予使用CSRF。
    # 跳过CSRF验证
    return csrf_exempt(view)

在APIview中的as_view()方法什么都没有做,只是调用了父类的as_view()方法.

as_view()会返回self.diapatch(),由于BookView没有实现这个方法,所以我们只有查看APIView中的dispatch()都做了那些工作

dispatch():和Django.views中的View类的dispatch()派遣相同,额外添加了一些功能

# Note: 在“派遣”需要被改写的情况下,可以在"as_view"范围内对CSRF进行豁免,以防止意外移除这一豁免。
def dispatch(self, request, *args, **kwargs):
    """
    和django.views中View的dispatch()调度差不多,
    但是有额外的钩子用于启动、终结和异常处理。
    """
    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)

        # 获取适当的程序处理方法,这里的调度和django  View的调度一样
        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
        
        # 调用HTTP请求处理方法,并返回
        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

APIView中的dispatch()和Django中的dispatch()类似,不同之处,APIView对request请求对象进行了重新封装

request:APIView对request对象进行了重新封装

 

 

def dispatch(self, request, *args, **kwargs):
    """
    `.dispatch()` is pretty much the same as Django's regular dispatch,
    but with extra hooks for startup, finalize, and exception handling.
    """
    self.args = args
    self.kwargs = kwargs
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?
    
    ....

默认的是django.core.handlers.wsgi.WSGIRequest对象,通过调用initialize_request()将其封装成rest_framework.request.Request。通过type(request)来查看

initialize_request():

def initialize_request(self, request, *args, **kwargs):
    parser_context = self.get_parser_context(request)

    # 返回了一个reuqest请求对象
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )

Request类: 完善request请求的一些注意事项

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) 

之后使用的request,都是restfromwork封装的Reqeust对象。

 

posted on 2018-12-05 19:50  成伤大大  阅读(158)  评论(0)    收藏  举报

导航