Django学习之FBV与CBV(五)
在前面的案例中,不管是注册还是登录,都包含了GET方法和POST方法,也就是说在视图的函数中,我们都得判断
是GET方法还是POST方法,如果是GET方法,就返回对应的模板文件并且渲染展示出来,如果是POST文件,就从前台
获取到输入的信息,然后在视图函数中获取并且依据获取到的信息做程序的下一步的判断,如见如下登录系统的视图函数
代码:
def login(request): if request.method=='GET': obj=UserInfoForm() return render(request,'login/login.html',locals()) elif request.method=='POST': obj=UserInfoForm(request.POST) if obj.is_valid(): data=obj.cleaned_data print(data,type(data)) c=UserInfo.objects.filter(**data) request.session['is_login']=True request.session['username']=data['username'] return redirect(to='login:index') else: return render(request,'login/login.html',{'obj':obj.errors})
这样的一种方式不是特别的友好,假设视图函数login中不仅仅有GET和POST方法,还有PUT,DELETE方法,那么
依据现在的模式,需要判断如果是PUT方法,继续写关于PUT方法的业务逻辑,如果是DELETE方法就继续写DELETE
的也许逻辑,很多的判断,这种模式成为FBV的模式,也就是基于函数的视图,那么有没有一种更加好的方式了?当然
是有的,它的模式就是CBV,也就是基于类的视图。但是有一点必须是要明确的,基于CBV的视图模式不会取代基于FBV
的视图模式的,只有适合自己的模式才是最好的模式。如果对这点模式还是不是很清楚,建议看如下的链接地址里面有
对应的案例说明,链接地址:
在本文中,要对基于函数的视图修改成基于类的视图,那么首先需要在django中导入views,导入的代码为:
from django import views
在views的包中,我们可以使用base.py模块中的View类,事实上在类View的构造函数中,就有我们经常常用的HTTP的
请求方法,就看实际中我们的使用场景,使用到的方法主要是as_view,见类View的源码:
class View: """ Intentionally simple parent class for all views. Only implements dispatch-by-method and simple sanity checking. """ http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def __init__(self, **kwargs): """ Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things. """ # Go through keyword arguments, and either save their values to our # instance, or raise an error. for key, value in kwargs.items(): setattr(self, key, value) @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) 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 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) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) def http_method_not_allowed(self, request, *args, **kwargs): logger.warning( 'Method Not Allowed (%s): %s', request.method, request.path, extra={'status_code': 405, 'request': request} ) return HttpResponseNotAllowed(self._allowed_methods()) def options(self, request, *args, **kwargs): """Handle responding to requests for the OPTIONS HTTP verb.""" response = HttpResponse() response['Allow'] = ', '.join(self._allowed_methods()) response['Content-Length'] = '0' return response def _allowed_methods(self): return [m.upper() for m in self.http_method_names if hasattr(self, m)]
那么下来我们需要对基于函数的视图进行修改,修改成基于类的视图,修改后的源码为:
class Login(views.View): def dispatch(self, request, *args, **kwargs): return super(Login, self).dispatch(request,*args,**kwargs) def get(self, request, *args, **kwargs): obj = UserInfoForm() return render(request, 'login/login.html',locals()) def post(self,request,*args,**kwargs): obj=UserInfoForm(request.POST) if obj.is_valid(): data=obj.cleaned_data c=UserInfo.objects.filter(**data) request.session['is_login']=True request.session['username']=data['username'] return redirect(to='login:index') else: return render(request,'login/login.html',{'obj':obj.errors})
见如上的代码,修改成基于类的视图函数后,在URL中,首先会调用到Login的类,然后就会调用到方法dispatch,
在方法dispatch中,类Login继承了View的类,同时也就继承了该类的方法,如果我们单纯的打印出super(Login, self)
.dispatch(request,*args,**kwargs)它的内容,可以看到它输出的内容是:
<HttpResponse status_code=200, "text/html; charset=utf-8">
也就是Response的对象,然后依据页面调用的方法,分发到具体的GET和POST请求的方法中,这一点是非常重要的,
如果在方法dispatch方法中,没有return返回Response的对象,那么也就无法分发到具体的GET和POST方法中。所以
在实际的Django开发中,看个人具体的使用习惯,如果是喜欢基于函数的视图,就使用FBV,如果想要更加简单,就使用
基于类的视图函数。
如您想系统的学习接口自动化测试,可以扫描如下二维码关注本人的课程,谢谢!