CBV(Class Base View)是类视图FBV(Func Base View)是函数视图
CBV简单使用
FBV小案例
from django.http import HttpResponse
from django.shortcuts import render
# Create your views here.
def book(request):
if request.method == "GET":
return HttpResponse("GET")
elif request.method == "POST":
return HttpResponse("POST")
CBV小案例
from django.views import View
from django.http import HttpResponse
class BookView(View):
def get(self, response):
return HttpResponse("View GET")
def post(self, response):
return HttpResponse("View POST")
CBV源码解析
这要从urls.py中讲起
from django.contrib import admin
from django.urls import path, include
from . import views
urlpatterns = [
path('func/', views.book),
path('view/', views.BookView.as_view()) # 这行将路由和类绑定 其中最奇怪的是 as_view()
]
as_view()做了什么?
# 这个装饰器表示只允许类去调用
@classonlymethod
def as_view(cls, **initkwargs): # 这里的cls就是我们的BookView
"""Main entry point for a request-response process."""
for key in initkwargs:
# 这边在检查 你使用的方法是否在合法的范围内 在View对象上方有写这个属性
# http_method_names = ["get","post","put","patch","delete","head","options","trace",]
if key in cls.http_method_names:
raise TypeError(
"The method name %s is not accepted as a keyword argument "
"to %s()." % (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):
# 重申一遍 cls 是 BookView 所以这里实例化的self就是BookView
self = cls(**initkwargs)
# BookView 没有setup()方法所以来到了View中寻找
"""
# 这里的self依然是 BookView 去做了一些数据绑定
def setup(self, request, *args, **kwargs):
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
"""
self.setup(request, *args, **kwargs)
# 如果没有 request 报错
if not hasattr(self, "request"):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
# 这里调用dispatch最后一步了
"""
def dispatch(self, request, *args, **kwargs):
# 他将我们的请求方法变成小写 又一次判断了是否合法
if request.method.lower() in self.http_method_names:
# 这边做了一个反射 如用的是POST那么会转化成post然后判断self也就是BookView中有没有这个post方法
# 如果没有则赋值为http_method_not_allowed
handler = getattr(
self, request.method.lower(), self.http_method_not_allowed
)
else:
handler = self.http_method_not_allowed
# 返回handler 这个就变成了我们的post或者get方法,最终as_view也就返回了这个
return handler(request, *args, **kwargs)
"""
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# __name__ and __qualname__ are intentionally left unchanged as
# view_class should be used to robustly determine the name of the view
# instead.
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.__annotations__ = cls.dispatch.__annotations__
# Copy possible attributes set by decorators, e.g. @csrf_exempt, from
# the dispatch method.
view.__dict__.update(cls.dispatch.__dict__)
# Mark the callback if the view class is async.
if cls.view_is_async:
view._is_coroutine = asyncio.coroutines._is_coroutine
# 最终其实就是返回了view的返回值dispath的返回值 也就是我们的get或者post等其他的函数
return view