CBV源码分析
DRF中中所有视图都是基于CBV形式完成, 所以分析其cbv源码, 了解drf的基本请求流程就比较有必要了.
urls.py
"""下面是一个通用的url路由""""
url(r'^books/$', views.Book.as_view())
"""as_view同样是drf视图类的入口"""
views.py
"""下面是一个通用的简单的基于drf的apiview的一个视图"""
class Book(APIView):
def get(self, request, *args, **kwargs):
# 这个接口提供两个接口来进行调用, 所以需要分开来进行判断
# 判断路由中是否包含pk
pk = kwargs.get('pk')
# pk有值, 代表是查单本书
if pk:
try:
book = models.Book.objects.get(pk=pk, is_delete=False)
except models.Book.DoesNotExist:
return Response({
'status': 1,
'msg': '图书不存在'
})
ser_data = serializers.BookModelSerializer(book).data
# 当没有查询单本书时, 即pk不存在的话, 默认进行查询所有图书
else:
books = models.Book.objects.filter(is_delete=False) # 要找没有被删除的书籍
ser_data = serializers.BookModelSerializer(books, many=True).data # 不要忘记添加many=True的条件, 序列化多个对象对象
return Response({
'status': 0,
'msg': '查询成功',
'result': ser_data
})
as_view入口分析
首先drf的apiview是继承自django中View, 并重写了as_view方法, 也就相当于改写了入口方法.
@classmethod
def as_view(cls, **initkwargs):
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# 直接禁用了csrf认证, 所以我们的post请求可以不携带csrftoken参数了.
return csrf_exempt(view)
上面是APIView的as_view方法, 重写的内容很简单, 只是将csrf认证禁用了, 并进行了一些参数的初始化工作. 接下来是重点, as_view方法调用了父类的as_view方法, 返回的结果才是url匹配后真正执行的内容, 也就是调用了dispatch方法来分发.
dispatch分析
"""django的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
# 视图类调用的方法.
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
上面的源码部分清晰的看出了, 最后我们的路由匹配成功后, 最后走的是as_view内层的view方法, 也就是说调用了view类的dispatch方法, 而APIView正式重写了这个dispatch方法, 在这里做了许多的事, 因此可以说, dispatch才是drf中APIView的真正入口函数.
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 重新封装了request对象
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
# 这里做了各种初始化工作, 包括频率,认证, 权限等的校验.
self.initial(request, *args, **kwargs)
# 和django中的一样, 需要符合对应的8种http请求方法, 才能正确走到对应的视图函数进行处理.
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