span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }.cm-searching {background: #ffa; background: rgba(255, 255, 0, .4);}.cm-force-border { padding-right: .1px; }@media print { .CodeMirror div.CodeMirror-cursors {visibility: hidden;}}.cm-tab-wrap-hack:after { content: ""; }span.CodeMirror-selectedtext { background: none; }.CodeMirror-activeline-background, .CodeMirror-selected {transition: visibility 0ms 100ms;}.CodeMirror-blur .CodeMirror-activeline-background, .CodeMirror-blur .CodeMirror-selected {visibility:hidden;}.CodeMirror-blur .CodeMirror-matchingbracket {color:inherit !important;outline:none !important;text-decoration:none !important;}.CodeMirror-sizer {min-height:auto !important;}
-->
li {list-style-type:decimal;}.wiz-editor-body ol.wiz-list-level2 > li {list-style-type:lower-latin;}.wiz-editor-body ol.wiz-list-level3 > li {list-style-type:lower-roman;}.wiz-editor-body li.wiz-list-align-style {list-style-position: inside; margin-left: -1em;}.wiz-editor-body blockquote {padding: 0 12px;}.wiz-editor-body blockquote > :first-child {margin-top:0;}.wiz-editor-body blockquote > :last-child {margin-bottom:0;}.wiz-editor-body img {border:0;max-width:100%;height:auto !important;margin:2px 0;}.wiz-editor-body table {border-collapse:collapse;border:1px solid #bbbbbb;}.wiz-editor-body td,.wiz-editor-body th {padding:4px 8px;border-collapse:collapse;border:1px solid #bbbbbb;min-height:28px;word-break:break-word;box-sizing: border-box;}.wiz-editor-body td > div:first-child {margin-top:0;}.wiz-editor-body td > div:last-child {margin-bottom:0;}.wiz-editor-body img.wiz-svg-image {box-shadow:1px 1px 4px #E8E8E8;}.wiz-hide {display:none !important;}
-->

引入:

        近期参与的项目是一个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.请看下文
 
    
    
      
 
    
 

 
                   
        

从FBV到CBV一(开始)的更多相关文章

  1. python 视图 (FBV、CBV ) 、Request 和Response对象 、路由系统

    一.FBV和CBV1.基于函数的view,就叫FBV(Function Based View) 示例: def add_book(request): pub_obj=models.Publisher. ...

  2. django请求生命周期,FBV和CBV,ORM拾遗,Git

    一.django 请求生命周期 流程图: 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post, ...

  3. django——FBV与CBV

    引言 FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. CBV CBV(class bas ...

  4. Django之FBV与CBV

    一.FBV与CBV FBV(function based views),即基于函数的视图:CBV(class based views),即基于类的视图,也是基于对象的视图.当看到这个解释时,我是很萌的 ...

  5. python 全栈开发,Day84(django请求生命周期,FBV和CBV,ORM拾遗,Git)

    一.django 请求生命周期 流程图: 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post, ...

  6. 一、虚拟环境.二、路由配置主页与404.三、2.x路由分发.四、伪静态.五、request对象.六、FBV与CBV.七、文件上传.

    一.虚拟环境 ''' 解决版本共存 1. 用pycharm选择File点击NewProject然后选择virtualenv创建一个纯净环境 2. 打开下载的目录将venv文件夹下的所有文件(纯净的环境 ...

  7. django基础 -- 4. 模板语言 过滤器 模板继承 FBV 和CBV 装饰器 组件

    一.语法 两种特殊符号(语法): {{ }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 二.变量 1. 可直接用  {{ 变量名 }} (可调用字符串, 数字 ,列表,字典,对象等) ...

  8. django中的FBV和CBV

    django中请求处理方式有2种:FBV 和 CBV 一.FBV FBV(function base views) 就是在视图里使用函数处理请求. 看代码: urls.py from django.c ...

  9. Django FBV和CBV -

    一.FBV和CBV 在Python菜鸟之路:Django 路由.模板.Model(ORM)一节中,已经介绍了几种路由的写法及对应关系,那种写法可以称之为FBV: function base view ...

  10. django中视图处理请求方式(FBV、CBV)

    FBV FBV(function base views) 就是在视图里使用函数处理请求. 在之前django的学习中,我们一直使用的是这种方式,所以不再赘述. CBV CBV(class base v ...

随机推荐

  1. JSP学习案例--,竞猜游戏

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...

  2. View的事件机制

    为了更好的研究View的事件转发,我们自定以一个MyButton继承Button,然后把跟事件传播有关的方法进行复写,然后添加上日志. import android.content.Context; ...

  3. Android中图片的三级缓存

    为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量.在当前的状况下,对于非wifi ...

  4. tensorflow卷积神经网络与手写字识别

    1.知识点 """ 基础知识: 1.神经网络(neural networks)的基本组成包括输入层.隐藏层.输出层.而卷积神经网络的特点在于隐藏层分为卷积层和池化层(po ...

  5. flutter shared_preferences 异步变同步

    前言 在开发原生iOS或Native应用时,一般有判断上一次安装的版本和当前版本是否是同一个版本,如果不是同一个版本,则要显示引导页,这个过程是把版本号持久化存储起来,在每一次启动时进行判断,这个过程 ...

  6. SQL学习(六)select into:复制表信息

    在实际工作中,可能需要将一个表中的数据复制到另一个表中,以供后续使用.此时可以用关键字select into(在MySQL中不支持select into,可使用insert into...select ...

  7. Jmeter实现简单web负载测试

    Jmeter实现简单web负载测试 简介 Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域. ...

  8. MySQL 按照数据库表字段动态排序 查询列表信息

    MySQL 按照数据库表字段动态排序 查询列表信息 背景描述 项目中数据列表分页展示的时候,前端使用的Table组件,每列自带对当前页的数据进行升序或者降序的排序. 但是客户期望:随机点击某一列的时候 ...

  9. 初探ASP.NET Web API (转)

    http://www.cnblogs.com/mejoy/p/6402821.html 什么是ASP.NET Web API? 官方的解释是 ASP.NET Web API is a framewor ...

  10. dokcer部署code-server web版vscode

    #dokcer部署code-server web版vscode codercom/code-server:latest不支持插件在线安装 codercom/code-server:v2目前为最新版1. ...