从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
]
 
 
        
# views.py import json from django.shortcuts import HttpResponse def create_book(request): return HttpResponse(json.dumps({'code': '20000'})) def update_book(request): # do something return HttpResponse(json.dumps({'code': '20000'})) def get_book(request): # do something return HttpResponse(json.dumps({'code': '20000'})) def delete_book(request): # do something return HttpResponse(json.dumps({'code': '20000'})) def create_author(request): return HttpResponse(json.dumps({'code': '20000'})) def update_author(request): # do something return HttpResponse(json.dumps({'code': '20000'})) def get_author(request): # do something return HttpResponse(json.dumps({'code': '20000'})) def delete_author(request): # do something return HttpResponse(json.dumps({'code': '20000'}))
 
 
 
 
 
 
 
 
 
 
 
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简化?当然可以,或者有的项目中会出现以下实现方式:
# urls.py urlpatterns = [ url(r'^book/$', views.book), url(r'^author/$', views.author), ]
 
 
 
 
 
 
 
 
 
 
 
1
# urls.py
2
urlpatterns = [
3
    url(r'^book/$', views.book),
4
    url(r'^author/$', views.author),
5
]
 
 
 
# views.py def book(request): if request.method == "GET": # get a book return HttpResponse(json.dumps({'code': '20000'})) elif request.method == "POST": # create a book return HttpResponse(json.dumps({'code': '20000'})) elif request.method == "PUT": # update a book return HttpResponse(json.dumps({'code': '20000'})) elif request.method == "DELETE": # delete a book return HttpResponse(json.dumps({'code': '20000'})) else: # method not be support return HttpResponse(json.dumps({'code': '40010'})) def author(request): if request.method == "GET": # get a author return HttpResponse(json.dumps({'code': '20000'})) elif request.method == "POST": # create a author return HttpResponse(json.dumps({'code': '20000'})) elif request.method == "PUT": # update a author return HttpResponse(json.dumps({'code': '20000'})) elif rrequest.method == "DELETE": # delete a author return HttpResponse(json.dumps({'code': '20000'})) else: # method not be support return HttpResponse(json.dumps({'code': '40010'}))
 
 
 
 
 
 
 
 
 
 
 
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中间件注释掉:
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', )
 
 
 
 
 
 
 
 
 
 
 
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就应该用以下方式实现:
# views.py from django.views.generic.base import View class Book(View): def get(self, request): # get a book return HttpResponse(json.dumps({'code': '20000'})) def post(self, request): # create a book return HttpResponse(json.dumps({'code': '20000'})) def put(self, request): # update a book return HttpResponse(json.dumps({'code': '20000'})) def delete(self, request): # delete a book return HttpResponse(json.dumps({'code': '20000'}))
 
 
 
 
 
 
 
 
 
 
 
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.请看下文
 
    
    
       
 
    

 
 
 
 
                   
        

转载于:https://www.cnblogs.com/wangbaojun/p/10933730.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值