• 从FBV到CBV一(开始)


    引入: 

            近期参与的项目是一个14年基于Django开发的web系统,因为项目早期的同事并未考虑前后端分离也未遵循标准的restful接口设计,现在在逐渐拆分微服务的过程深深感到遵从标准restful设计的重要性。在这里和大家分享一下自己的拙见: 
            拿到手的项目全部基于FBV(function base views)设计,这样的设计导致的情况就是会有一堆url,一个url路由映射一个function,一个function完成一个功能,比如一下例子:
            
     
     
     
     
     
     
     
     
     
     
     
    1
    # urls.py
    2
    3
    urlpatterns = [
    4
        url(r'^create_book/$', views.create_book),
    5
        url(r'^update_book/$', views.update_book),
    6
        url(r'^get_book/$', views.get_book),
    7
        url(r'^delete_book/$', views.delete_book),
    8
    9
        url(r'^create_author/$', views.create_author),
    10
        url(r'^update_author/$', views.update_book),
    11
        url(r'^get_author/$', views.get_author),
    12
        url(r'^delete_author/$', views.delete_author),
    13
    14
    ]
     
     
            

     
     
     
     
     
     
     
     
     
     
     
    1
    # views.py
    2
    import json
    3
    from django.shortcuts import HttpResponse
    4
    5
    6
    def create_book(request):
    7
        return HttpResponse(json.dumps({'code': '20000'}))
    8
    9
    10
    def update_book(request):
    11
        # do something
    12
        return HttpResponse(json.dumps({'code': '20000'}))
    13
    14
    15
    def get_book(request):
    16
        # do something
    17
        return HttpResponse(json.dumps({'code': '20000'}))
    18
    19
    20
    def delete_book(request):
    21
        # do something
    22
        return HttpResponse(json.dumps({'code': '20000'}))
    23
    24
    25
    def create_author(request):
    26
        return HttpResponse(json.dumps({'code': '20000'}))
    27
    28
    29
    def update_author(request):
    30
        # do something
    31
        return HttpResponse(json.dumps({'code': '20000'}))
    32
    33
    34
    def get_author(request):
    35
        # do something
    36
        return HttpResponse(json.dumps({'code': '20000'}))
    37
    38
    39
    def delete_author(request):
    40
        # do something
    41
        return HttpResponse(json.dumps({'code': '20000'}))
     
     
            其实单纯的从功能实现来看,这种写法完全没有问题,但是有人问题就在于接口过多,不容易维护,前端开发者会很头疼,要记下如此多的接口
            那能不能讲url简化?当然可以,或者有的项目中会出现以下实现方式:

     
     
     
     
     
     
     
     
     
     
     
    1
    # urls.py
    2
    urlpatterns = [
    3
        url(r'^book/$', views.book),
    4
        url(r'^author/$', views.author),
    5
    ]
     
     
     

     
     
     
     
     
     
     
     
     
     
     
    1
    # views.py
    2
    def book(request):
    3
        if request.method == "GET":
    4
            # get a book
    5
            return HttpResponse(json.dumps({'code': '20000'}))
    6
        elif request.method == "POST":
    7
            # create a book
    8
            return HttpResponse(json.dumps({'code': '20000'}))
    9
        elif request.method == "PUT":
    10
            # update a book
    11
            return HttpResponse(json.dumps({'code': '20000'}))
    12
        elif request.method == "DELETE":
    13
            # delete a book
    14
            return HttpResponse(json.dumps({'code': '20000'}))
    15
        else:
    16
            # method not be support
    17
            return HttpResponse(json.dumps({'code': '40010'}))
    18
    19
    20
    def author(request):
    21
        if request.method == "GET":
    22
            # get a author
    23
            return HttpResponse(json.dumps({'code': '20000'}))
    24
        elif request.method == "POST":
    25
            # create a author
    26
            return HttpResponse(json.dumps({'code': '20000'}))
    27
        elif request.method == "PUT":
    28
            # update a author
    29
            return HttpResponse(json.dumps({'code': '20000'}))
    30
        elif rrequest.method == "DELETE":
    31
            # delete a author
    32
            return HttpResponse(json.dumps({'code': '20000'}))
    33
        else:
    34
            # method not be support
    35
            return HttpResponse(json.dumps({'code': '40010'}))
     
     
           这里可以看到url是已经简化了,所有的功能都在function中做了实现,通过requests.method选择对应的处理逻辑
            通过postman测试一下:
            GET:
                    
     
            POST:            
                    
           
       PUT,DELETE和POST请求的结果是一样的,因为django的csrf验证阻止我们的请求,这里先不做csrf token验证,为了方便先将csrf token中间件注释掉:

     
     
     
     
     
     
     
     
     
     
     
    1
    MIDDLEWARE_CLASSES = (
    2
        'django.contrib.sessions.middleware.SessionMiddleware',
    3
        'django.middleware.common.CommonMiddleware',
    4
        #'django.middleware.csrf.CsrfViewMiddleware',
    5
        'django.contrib.auth.middleware.AuthenticationMiddleware',
    6
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    7
        'django.contrib.messages.middleware.MessageMiddleware',
    8
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    9
        'django.middleware.security.SecurityMiddleware',
    10
    )
     
     
                接下来重新提交,就可以返回正确的response了。     
     
           好像是达到了简化ur的l目的,但是还是通过FBV方式实现的接口,function体的内容过多,逻辑分支很多,要对请求进行判断并且实现对应的逻辑分支。代码整体上并不优雅,但是这样的代码有问题吗?并没有,只是CBV提供了更好的方式来实现接口的定义。
           我们知道FBV就是在视图里使用函数处理请求。其实CBV就是在视图里使用类处理请求。
           如果我们要通过类的方式处理请求,那上面的function就应该用以下方式实现:

     
     
     
     
     
     
     
     
     
     
     
    1
    # views.py
    2
    from django.views.generic.base import View
    3
    class Book(View):
    4
        def get(self, request):
    5
            # get a book
    6
            return HttpResponse(json.dumps({'code': '20000'}))
    7
    8
        def post(self, request):
    9
            # create a book
    10
            return HttpResponse(json.dumps({'code': '20000'}))
    11
    12
        def put(self, request):
    13
            # update a book
    14
            return HttpResponse(json.dumps({'code': '20000'}))
    15
    16
        def delete(self, request):
    17
            # delete a book
    18
            return HttpResponse(json.dumps({'code': '20000'}))
     
     
            这里我们继承了View,并且在Book类中定义了get,post,put,delete方法,我们其实,当一个请求过来的时候会交给对应的方法进行处理,比如,我们有一个请求是GET请求,那就应该交给get方法处理,那这是怎么实现的呢?    
            我们知道在django中,一个请求的生命周期:
    #1.wsgi,请求封装后交给web框架 (Flask、Django)     
    #2.中间件,对请求进行校验或在请求对象中添加其他相关数据,例如:csrf、request.session     - 
    #3.路由匹配 根据浏览器发送的不同url去匹配不同的视图函数    
    #4.视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:orm、templates => 渲染     - 
    #5.中间件,对响应的数据进行处理。 
    #6.wsgi,将响应的内容发送给浏览器。
         FBV和CBV在前两步是没有什么区别的,重点就在于第三步路由匹配:
         FBV中路由匹配
                url(r'^book/$', views.book),看上去很容易理解,将url是/book/的请求交给views.py中的book函数处理
         CBV中路由匹配
                url(r'^book/$', Book.as_view(), name='book'), Book是我们在views.py中定义的类,继承于View,那as_view()是从哪来的?我们没有在book中定义,而是父类(View)中定义的.
         CBV是怎么将method交给对应方法处理的呢?来看源码:
              
         as_view是一个闭包函数,返回值是内部view,我们只需要关心view部分,这里的request就是之前在FBV中使用的request,前几行就是将参数封装到类属性,重点在于self.dispatch,所有到CBV的请求都会以dispatch为入口,这里的self就是我们上面定义的Book类,
         先会在Book类中找dispatch方法,我们没有定义,所以向上找,就用Book类的父类APIView类的despatch方法,接下来我们看APIView类的dispatch都做了什么:
        
        这里的self.initialize_request做了什呢?注意看参数,(request, *args, **kwargs)这里的request是原本FBV中的第一个参数,那这个request参数是怎么来的?
        request由来:当一个页面被请示时,Django创建一个包含请求元数据的HttpRequest对象。然后Django调入合适的视图,把HttpRequest作为视图函数的第一个参数传入。每个视图要负责返回一个HttpResponse对象。
        initialize_request()分析:
        这里将原先的requet封装于Request类中
        这里标记的3处,分别对应解析器,认证器,渲染器,这里先讲get_authenticators.请看下文
     
        
        
          
     
        

     
    
    
     
                       
            
  • 相关阅读:
    Azure SQL Database (1) 用户手册
    Windows Azure Web Site (17) Azure Web Site 固定公网IP地址
    MongoDB数据文件内部结构
    压缩 MongoDB 的数据文件
    服务器如何选择网络带宽(转)
    刀片服务器和磁盘阵列卡(RAID)技术---永和维护(转)
    Solr打分出错
    Solr添加SolrDocument报错
    解决Windows Git Bash中文乱码问题
    HAProxy的独门武器:ebtree
  • 原文地址:https://www.cnblogs.com/wangbaojun/p/10933730.html
Copyright © 2020-2023  润新知