目录
FBV和CBV表象
view.py
# FBV
def index(request):
if request.method == "GET":
return JsonResponse({'status': True, 'message': "GET"})
elif request.method == "POST":
return JsonResponse({'status': True, 'message': "POST"})
# CBV
class IndexView(View):
def get(self, request):
return JsonResponse({'status': True, 'message': "POST"})
def post(self, request):
return JsonResponse({'status': True, 'message': "POST"})
def put(self, request):
return JsonResponse({'status': True, 'message': "PUT"})
def delete(self, request):
return JsonResponse({'status': True, 'message': "DELETE"})
url.py
urlpatterns = [
# path('admin/', admin.site.urls),
path('index/', index),
path('IndexView/', IndexView.as_view()),
]
发现FBV
通过if
和request.method
来区分请求方式而CBV
通过方法来区分。
在url
中他们的调用方式不同,FBV
直接传递函数名,CBV
还需要调用类视图下的as_view()
方法才可以。
as_view()做了什么?
IndexView.as_view()
既然是类方法,那么IndexView
中有 as_view
方法么?没有,那么我们来看看父类View
中。
View
中有 as_view
方法,那么我们截取其中有用的代码来看看他做了什么?
class View:
http_method_names = [
"get",
"post",
"put",
"patch",
"delete",
"head",
"options",
"trace",
]
@classonlymethod
def as_view(cls, **initkwargs):
# view函数
def view(request, *args, **kwargs):
# 创建类实例
self = cls(**initkwargs)
# 做了个检查和参数传递
self.setup(request, *args, **kwargs)
if not hasattr(self, "request"):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
# 调用 dispath并返回
return self.dispatch(request, *args, **kwargs)
return view
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
# 如果你的方法中有 get 且没有 head那么 head = get
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
# 将方法转成小写 http_method_names就是类开头定义的列表
if request.method.lower() in self.http_method_names:
# 假设 request.method.lower() = get 那么这句话就是获取你的get方法
handler = getattr(
self, request.method.lower(), self.http_method_not_allowed
)
else:
handler = self.http_method_not_allowed
# 调用并返回你所调用的方法
return handler(request, *args, **kwargs)
这样就很清晰能看出,as_view()
返回了一个view
函数,这样就在url
的path
方法中和FBV
相同了。被调用后通过dispath()
调用了你所定义的方法,get
或者post
或者其他方法。
drf的View
view.py
from rest_framework.response import Response
from rest_framework.views import APIView
class RFWView(APIView):
def get(self, request):
return Response("drf view get")
url.py
urlpatterns = [
path('RFWView/', RFWView.as_view()),
]
RFWView
继承了APIView
那么我们来看看DRF
的APIView
中as_view()
是如何写的(摘取重要代码)
class APIView(View):
def as_view(cls, **initkwargs):
...
# 调用父类,调用的就是django原生的as_view
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
# 避免csrf验证
return csrf_exempt(view)
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 还是django原生request
request = self.initialize_request(request, *args, **kwargs)
# 在这 request 变成了 drf 的 request
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# 实现了django原生dispatch功能
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