APIView源调用流程
1.首先从django项目跟url开始
我们已get请求publish页面为例,如下先在跟目录找到
r'^publish/' ---->执行对应的函数 views.PublishView.as_view()
urls.py:
from django.conf.urls import url from django.contrib import admin from app01 import views
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^publish/',views.PublishView.as_view())]
查找顺序:views.py----->PublishView------>APIView
文字说明:先查找views.py下的PublishView,看看自定义类是否有as_view方法,没有就开始向父类APIView查找,在APIView中有as_view方法,其实通过32行
代码我们知道APIView执行的还是它父类View中的as_view方法返回了一个内嵌的view函数,这个函数执行的结果我们可以看到得到的是一个
self.dispatch(request, *args, **kwargs),这个self很关键,通过 self = cls(**initkwargs),我们知道这个self就是调用这个类方法的一个实例
谁来调用这个函数self就是谁的实例,所以在我们这个例子中self指代的及时PublishView的实例对线,所以在调用dispatch方法先从自定义的PublishView中找
,我们这个class中没有dispatch所以开始找它的父类APIView,在APIView中找到了我们需要的dispatch,所以开始执行这个分发,走到这里我们可以看到
rest_framework在APIView接口中和CBV的区别就是APIVIew自定义了一个dispatch对CBV的view方法中的dispatch进行了一个拦截,有点类似我们组件中的
通用父类和自定义配置类
1 # views.py: 2 3 from rest_framework.views import APIView 4 5 class PublishView(APIView): 6 7 def get(self,request): 8 pass 9 10 11 def post(self,request):12 pass13 14 # rest_framework/views.py15 16 class APIView(View):17 settings = api_settings18 schema = DefaultSchema()19 20 @classmethod21 def as_view(cls, **initkwargs):22 23 if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):24 def force_evaluation():25 raise RuntimeError(26 'Do not evaluate the `.queryset` attribute directly, '27 'as the result will be cached and reused between requests. '28 'Use `.all()` or call `.get_queryset()` instead.'29 )30 cls.queryset._fetch_all = force_evaluation31 32 view = super(APIView, cls).as_view(**initkwargs)33 view.cls = cls34 view.initkwargs = initkwargs35 36 return csrf_exempt(view)37 38 39 def dispatch(self, request, *args, **kwargs):40 41 self.args = args42 self.kwargs = kwargs43 request = self.initialize_request(request, *args, **kwargs)44 self.request = request45 self.headers = self.default_response_headers # deprecate?46 47 try:48 self.initial(request, *args, **kwargs)49 50 # Get the appropriate handler method51 if request.method.lower() in self.http_method_names:52 handler = getattr(self, request.method.lower(),53 self.http_method_not_allowed)54 else:55 handler = self.http_method_not_allowed56 57 response = handler(request, *args, **kwargs)58 59 except Exception as exc:60 response = self.handle_exception(exc)61 62 self.response = self.finalize_response(request, response, *args, **kwargs)63 return self.response
class View(object): http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] @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 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