zoukankan      html  css  js  c++  java
  • Django之FBV与CBV

      一、FBV与CBV

      FBV(function based views),即基于函数的视图;CBV(class based views),即基于类的视图,也是基于对象的视图。当看到这个解释时,我是很萌的,我仔细回想了一下,哪里有基于类的视图啊,怎么我之前写的视图都是一个一个的函数啊,奇怪了,很多人都应该和我一样蒙(大佬除外哈)。没错我之前写的所有的视图都是基于函数的,所以今天咋们不去扯什么是FBV了,实在不知道的,可以看看在今天之前的所有视图,绝对都是FBV模型的(这个我敢打包票)。

      二、CBV的实现代码

      当听到基于class时,就会想到对象,瞬间有点慌,总感觉对象这个东西要比函数难,没有那么好理解,这应该是大多数人的共性,但在python中处处皆对象,你不想碰他就不能碰他?????不可能的,要想使你的代码更有水平,那你就避不开对象,而且对于开发来说,肯定都是要用到对象。其实哈这个基于对象的视图很好理解。

      1,先写视图

    from django.shortcuts import render,HttpResponse
    from django.views import View
    class myview(View):
        def get(self,request):
            return render(request,'login.html')
        def post(self,request):
            return HttpResponse('post请求')

      2,写一个登录的页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="" method="post">
            {% csrf_token %}
            <label for="user">用户名:</label>
            <input type="text" name="user" id="user">
            <label for="pwd">密码:</label>
            <input type="password" name="pwd" id="pwd">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>

      3,url

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('login/', views.myview.as_view()),
    ]

      4,分析过程

      首先我们得看url,当请求路径是login时,会调用views里面的myview类的一个方法as_view,在这里我们先不管这个方法到底干了啥,只是说说执行流程。在浏览器地址栏输入login路径时,用的是get请求,它就会去调用myview类下的自己写的get,然后饭后一个登录页面;得到页面后输入用户名和密码之后点击提交按钮,又往login路径发送了一个post请求,这时就会调用myview类下的自己写的post方法,返回一个‘post请求’字符,这就是整个过程,从两个流程来看,大概可以猜出,整个过程中,django会判断请求的方式,不同的请求方式调用相应的方法

      三、分析源码

      既然在我自定义的myview类里没有写任何关于请求方式的逻辑,那我们应该猜测到,在myview继承的View类里面肯定有相关的东西(大佬经验,阅读源码时,看不懂就不要去看,不要去分析,只看我们需要的)。

      1,源码

    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)]

      2,剖析

      在url里面,我们可以看到当请求过来后,执行的是views.myview.as_view(),所以我们去看看as_view()这个方法到底干了啥,首先在我们自定义的myview类里面没有这个方法,那就去父类View里找。

     上面说过看不懂的就不要看,所以我把看不懂的给删除了
     @classonlymethod
    def as_view(cls, **initkwargs): #这是as_view方法

        def view(request, *args, **kwargs): #这是as_view方法里嵌套一个方法view self = cls(**initkwargs) #这是用myview类实例化的一个对象self
           return self.dispatch(request, *args, **kwargs) #这是用实例化对象self去调用dispatch方法,然后作为view方法的返回值值
        return view #这是返回view这个方法,也就是把view方法的返回值作为as_view的返回值,

      接下来我们得去看看dispatch方法干了什么,首先也得从自定义的myview类里找dispatch方法,没找到,然后去父类View里找,

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
    def dispatch(self, request, *args, **kwargs):       #这是dispatch方法
        if request.method.lower() in self.http_method_names:      #这是把请求的方法取出来,然后小写,看有没有在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)      #返回请求方式对应方法的执行结果
    比如说是get请求进来后,它就利用反射会去myview里面拿到一个叫get的方法,在我的myview类下就有我自定义的get方法,然后执行它,得到一个HTTPResponse对象,返回给dispatch方法,dispatch方法又把这个HTTPResponse对选哪个返回给了view方法,
    view方法又把这个对象返回给as_view方法,as_view方法又把这个作为响应返回给客户端,这整个过程简化中间的过程就会变成,get方法返回一个HTTPResponse对象给客户端
  • 相关阅读:
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    centos 编码问题 编码转换 cd到对应目录 执行 中文解压
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    Android MVP 十分钟入门!
    mysql备份及恢复
    mysql备份及恢复
    mysql备份及恢复
  • 原文地址:https://www.cnblogs.com/12345huangchun/p/10475000.html
Copyright © 2011-2022 走看看