Django 视图之FBV 与 CBV
- FBV(function base views) 基于函数的视图,就是在视图里使用函数处理请求
- CBV(class base views) 基于类的视图,就是在视图里使用类处理请求
FBV
FBV基于函数的这种类型我们一直在使用,比如:
\'\'\'urls.py\'\'\'urlpatterns = [path("login/", views.login),]\'\'\'views.py\'\'\'from django.shortcuts import render,HttpResponsedef login(request):if request.method == "GET":return HttpResponse("GET 方法")if request.method == "POST":username = request.POST.get("user")password = request.POST.get("pwd")if username == "Hammer" and password == "123":return HttpResponse("POST 方法")else:return HttpResponse("POST other方法")# 访问 http://127.0.0.1:8000/login/ 返回:---》GET 方法
CBV
基于类的视图,就是使用了类来处理用户的请求,不同的请求我们可以在类中使用不同方法来处理,这样大大的提高了代码的可读性;
基于类的视图实现主要还是通过父类 View 提供的一个静态方法 as_view() ,as_view 方法是基于类的外部接口, 他返回一个视图函数,调用后请求会传递给 dispatch 方法,dispatch 方法再根据不同请求来处理不同的方法。
定义的类要继承父类 View,所以需要先引入库:
\'\'\'urls.py\'\'\'urlpatterns = [path(\'func2/\',views.Func2.as_view()),]\'\'\'views.py\'\'\'from django.shortcuts import render,HttpResponsefrom django.views import Viewclass Func2(View):def get(self,request):return HttpResponse(\'get 方法\')def post(self,request):return HttpResponse(\'post 方法\')# 访问:http://127.0.0.1:8000/func2/ 返回 --》:GET 方法
总结
1、可以通过查看
as_view()
源码也可以发现,返回了
view
函数的内存地址,那么运行
path(\'func2/\',views.Func2.as_view())
,就相当于运行了
path(\'func2/\',views.view
,因为
Func2.as_view()
的返回值是
view
,这样看起来CBV基于类的本质也是基于函数,在满足func2的情况下触发视图函数,源码展示如下:
@classonlymethod # 绑定给类的def as_view(cls, **initkwargs):"""Main entry point for a request-response process."""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) # self = Func2() ,生成自己写的类的对象if hasattr(self, \'get\') and not hasattr(self, \'head\'):self.head = self.getself.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__)return self.dispatch(request, *args, **kwargs)view.view_class = clsview.view_initkwargs = initkwargs# take name and docstring from classupdate_wrapper(view, cls, updated=())# and possible attributes set by decorators# like csrf_exempt from dispatchupdate_wrapper(view, cls.dispatch, assigned=())return view
dispatch
方法可以从继承的父类中查找,
View
# dispatch源码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.if request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(), self.http_method_not_allowed)# getattr反射可以通过字符串获取对象的属性或方法,self自己写的类产生的对象,如果拿不到请求方法,报错http_method_not_allowed,最后可以看出,handler就是我们自己写的方法,通过不同请求来触发else:handler = self.http_method_not_allowedreturn handler(request, *args, **kwargs)# 执行我们写的同名(get)请求方法,并返回该方法的返回值
ps:
http_method_names = [\'get\', \'post\', \'put\', \'patch\', \'delete\', \'head\', \'options\', \'trace\']
,八个基本请求方式