REST framework(一) APIView

Restframework

CBV(class based view)

CBV(class base views) 就是在视图里使用类处理请求。

Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:

  1. 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
  2. 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性

写一个简单CBV视图:

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^login/', views.LoginView.as_view()),
]

app01下的views.py

from django.views import View
from django.shortcuts import render,HttpResponse

class LoginView(View):

    def get(self,request):
        return render(request,"login.html")

    def post(self,request):
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")

        if 1:
            return HttpResponse("OK")

​ 当我们在浏览器中发送post或get的url请求,就可以进入视图中的得到请求的响应内容。这个过程我们需要从源码中进行深入了解。

url调用三步走:

url(r'^login/', views.LoginView.as_view()),
url(r'^login/', View.as_view()),
url(r'^login/', View.view),

Django中View的原码:

class View(object):
    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        for key, value in six.iteritems(kwargs):
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        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
            '''要知道此时的self是谁,才可理顺下一步持行方向。如果View的子类中有定义了dispatch方法就用子类的,如果没有就用View的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=())
        return view

    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)

Django的url是将一个请求分配给可调用的函数,CBV提供了一个as_view()类方法,调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()方法,dispatch()方法会根据request的method的不同调用相应的方法来处理request(如get(),post()等)。到这里,这些方法和function-based view差不多了,要接收request,得到一个response返回。如果方法没有定义,会抛出HttpResponseNotAllowed异常。

REST framework中的APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIView与View的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
支持定义的属性:
  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

我们来写一个小例子了解一下它的执行流程。

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^authors/',views.Authors_view.as_view()),
]

app01下的views.py

from django.shortcuts import render,HttpResponse
from app01.models import Author
from rest_framework.views import APIView
from django.core.serializers import serialize

class Authors_view(APIView):
    def get(self,request):
        ret=Author.objects.all()
        b=serialize('json',ret)
        return HttpResponse(b)

url调用的过程四步走:

 url(r'^authors/',views.Authors_view.as_view()),
 url(r'^authors/', APIView.as_view()),
 url(r'^authors/', View.as_view()),
 url(r'^authors/', View.view),

看一下REST framework中的APIView中的部分源码来分析其中的具体过程。

from django.views.generic import View

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)

    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

​ 从源码中我们看至APIView和Django中的View是继承的关系,它非富了View的工能。当我们使用APIView时我们需要了解它的代码执行流程。就以上面的例子为例。

  • 当浏览器发送/authors/url请求路径的时候,就会走到url(r'^authors/',views.Authors_view.as_view()),里面。
  • 我们知道Authors_view类是继承了APIView。所以我们要进入APIView里,发现APIView.as_view()中有这样一行代码 view = super(APIView, cls).as_view(**initkwargs)
  • 此时的super,就是Django中的View类。所以接下来代码执行就到View.as_view()中,调用这个方法,会创建一个类的实例。
  • 注意:当执行到return self.dispatch(request, *args, **kwargs)时候,此时的self,不是View而是APIView.
  • 所以接下来进入APIVIew.dspatch()中执行分发。通过实例调用dispatch()方法,根据request的method的不同调用相应的方法来处理request(如get(),post()等)。

你可能感兴趣的:(REST,framework,Django)