FBV 开发模式:
-
FBV开发模式 全名为:
function based views, 是一种基于函数的视图调用,他的优点就是简单上手,不需要继承, 所以我们也不需要去阅读很多底层代码,我们只需要在函数视图中写逻辑即可,缺点就是不符合python的面向对象的思想, 也就是不可以去继承和多态。 -
我们最开始使用Django时候基本都是 FBV开发模式, 这里我们给出一个例子.
在 urls.py 中
#urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('login.html', views.login, name="login"),
]
在views.py中
from django.shortcuts import HttpResponse
from django.shortcuts import render
def login(request):
if request.method == "GET":
return render(request, "xxx.html", locals())
else:
return HttpResponse("ok")
在urls.py 中Django也给我们注释了
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
CBV 开发模式
-
CBV开发模式, 全称为
class based views是一种基于类的视图函数调用,符合python的面向对象思想, 可以完好的继承和多态, CBV开发模式将各种方式用函数分开,实现了功能的分离, 比如可以直接使用 get(), post() 之类的方法, 同时省去了我们用 if 进行逻辑的判断, 提高了代码的可读性, 但是也有弊端, 如果我们的代码不是很规范,或者继承的类过于多的时候,CBV开发模式这个时候,就不是一个很好的选择,而选择FBV开发模式。一般用CBV开发模式用的更多一点。 -
下面我们举例看一看 CBV开发模式的调用方式
在urls.py中
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
# urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('', views.Home.as_views(), name="home"),
]
在views.py文件中
from django.views import View
class Home(View): #需要继承自View类
def get(self,request):
return HttpResponse("ok")
def post(self,request):
pass
使用这个方式我们需要继承一个类 from django.views import View 我们创建的类,就必须继承这个类, 不然就无法实现逻辑分发的功能, 那这个CBV开发模式是怎么实现的呢?
CBV开发模式如何实现
View源码
进入 Views 这个类, 第一个就可以看到 http_method_names , 这是一个列表,里面包括各种请求的方式, Views类里面封装了这些方法, 可以让我们直接使用 get(), post() … 之类的方法就直接调用, 省去了if判断, 那继续往下看。
接下来 我们看 as_views() 方法, 因为我们在配置路由的时候,调用了这个方法。
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(
'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):
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__
)
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
阅读源码我们可以知道, 前面在 for 循环 里面进行了一些异常的判断和抛出, 然后就是 def views() 函数, 之后,调用了 update这个方法, 通过继续观察, 还是其关键作用的还是下面的 update() 这个方法, 参数中将 view, cls.dispatch, 其实都是这个类的方法, 我们找到 dispach() 方法。
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)
dispatch 中文就是调度,分发的意思, 而且在这个源码中, 也给了提示, 就是调度,抛开这些, 我们阅读源码。
- 如果我们的方法名小写 在 这个 self.http_method_names: 里面, 也就是在规定的方法里面, 那么就去取这个方法名的函数, 最后返回给 Handler,进行下面的操作, 最后实现了 请求的分发, 否则就会抛出错误异常。
- 接下来就是到Handler
CBV开发模式如今已经迭代很多,django-rest-framework 提供了更多的继承类,CreateAPIView,ListAPIView,等等,都有不同的使用场景。