Django FBV和CBV的开发模式对比分析,让你轻松掌握视图开发技巧

558 阅读4分钟

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源码

image.png

进入 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,等等,都有不同的使用场景。

扫码关注我的公众号

有追求的开发者