zoukankan      html  css  js  c++  java
  • Django Rest framework 框架

    一、开发模式:  

      1. 普通开发方式(前后端放在一起写)

      2. 前后端分离(前后台通过ajaxo交互)

        后端(django rest framework写的) <----ajaxo--->  前端(vue写的) <----- >  用户

        好处:

    二、后端开发

        为前端提供url(API的开发或者接口的开发)

        注:永远返回HttpResponse

    路由

    from django.conf.urls import url
    from django.contrib import admin
    
    
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^users/', views.users),
    ]

    视图   ( FBV:function base view   基于函数的视图 如下)

    import json
    
    
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    
    def users(request):
        user_list = ['zgr','oldboy']
        return HttpResponse(json.dumps(user_list))

    后端的开发   http://127.0.0.1:8000/users/  只要访问这个URL就返回所有用户列表如下: 这就是接口的开发!

    三、Django中的FBV和CBV

      FBV:function base view   基于函数的视图

        函数作为视图函数

        当访问URL时,函数执行了

      CBV:class base view       基于类的视图    基于反射实现根据请求方式不同,执行不同的方法。

        当访问URL的时候,这个类里面还可以写很多方法,这个类里那个方法被执行了?先.这个类再点这个方法。函数嵌套类里面。如果以GET 方式请求,就会执行get方法就会自动会被执行。

    视图:

    # 这个类必须继承django的这个View
    from django.views import View
    
    class StudentsView(View):
        def get(self, request, *args, **kwargs):
            return HttpResponse('GET')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def putch(self, request, *args, **kwargs):
            return HttpResponse('PUTCH')

    路由:

    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),# 路由这里必须是类.as_view()   这是固定搭配
        url(r'^students/', views.StudentsView.as_view()),
    ]

    这样一个CBV就写完了。以不同的方式来执行,就会有不同的函数自动帮你执行了。

    HTTP请求的本质基于socket来做的,浏览器发一个请求本质上发了一堆字符串/r/n分割 ,做路由匹配,匹配成功,如果是FBV的话执行它对应的函数。但是如果是CBV怎么找到方法?通过反射!

    反射

    什么是反射?

      用在属性操作,之前是通过点操作属性。

      在python3中,统一了类与类型的概念(定义一个类就是一个类型,基本的数据类型字符串,列表。。。都是类)。

      通过字符串来反射到真正的属性身上,来进行属性操作。---->通过字符串来操作类或对象的属性。

      让客户自己输入要执行的操作,输入的是字符串,就要用字符串来反射到真正的属性(数据属性,函数属性...)身上.

    python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,这四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

    isinstance 用它来判断是否是一个实例。也可以用来判断数据类型

    issubclass 判断一个类是否是另一个类的子类。

    在python3中,统一了类与类型的概念(定义一个类就是一个类型,基本的数据类型字符串,列表。。。都是类)。

    Python中一切皆对象。

    class Foo(object):
     
        def __init__(self):
            self.name = 'wupeiqi'
     
        def func(self):
            return 'func'
     
    obj = Foo()
     
    # #### 检查是否含有成员 ####
    hasattr(obj, 'name')
    hasattr(obj, 'func')
     
    # #### 获取成员 ####
    getattr(obj, 'name')
    getattr(obj, 'func')
     
    # #### 设置成员 ####
    setattr(obj, 'age', 18)
    setattr(obj, 'show', lambda num: num + 1)
     
    # #### 删除成员 ####
    delattr(obj, 'name')
    delattr(obj, 'func')
    那么问题来了?
    a、上述访问对象成员的 name 和 func 是什么? 
    答:是变量名
    b、obj.xxx 是什么意思? 
    答:obj.xxx 表示去obj中或类中寻找变量名 xxx,并获取对应内存地址中的内容。
    c、需求:请使用其他方式获取obj对象中的name变量指向内存中的值 “alex”

    d、比较三种访问方式

    • obj.name
    • obj.__dict__['name']
    • getattr(obj, 'name')

    四、列表生成式 

    class Foo:
        pass
    
    class Bar:
        pass
    
    v=[item() for item in [Foo,Bar]]
    print(v)

    v就是对象列表里面,就是Foo的对象和Bar的对象。

    打印结果:
    [<__main__.Foo object at 0x1029d1358>, <__main__.Bar object at 0x1029d1320>]
    v=[]
    for i in [Foo,Bar]:
        obj=i()
        v.append(obj)

    五、面向对象编程   类    封装

    • 面向对象:对函数进行分类和封装,让开发“更快更好更强...”

      面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。

      类就是一个模板,模板里可以包含多个函数,函数里实现一些功能

      对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

    • class是关键字,表示类
    • 创建对象,类名称后加括号即可

    面向对象三大特性

    一、封装

    封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

    所以,在使用面向对象的封装特性时,需要:

    • 将内容封装到某处
    • 从某处调用被封装的内容

    第一步:将内容封装到某处

    # 对同一类方法封装到了同一类里面
    class File:
        文件的增删改查
    
    
    class DB:
        数据库的增删改查
    
    
    # 将数据封装到对象中(一个类实例化就是执行类的init方法得到一个对象)
    class File:
        def __init__(self,a1,a2):  #  self=obj
            self.a1=a1   #obj.a1=a1
            self.xxx=a2   #obj.xxx=a2
        def get..
        def put..
        def delete..
        def post..
    
    obj1 = File(123,234)

    self 是一个形式参数,当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1

                                  当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2

    所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。

     1 class Foo:
     2  
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6  
     7 obj1 = Foo('wupeiqi', 18)
     8 print obj1.name    # 直接调用obj1对象的name属性
     9 print obj1.age     # 直接调用obj1对象的age属性
    10  
    11 obj2 = Foo('alex', 73)
    12 print obj2.name    # 直接调用obj2对象的name属性
    13 print obj2.age     # 直接调用obj2对象的age属性
    View Code

    2、通过self间接调用被封装的内容

    执行类中的方法时,需要通过self间接调用被封装的内容

     1 class Foo:
     2   
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6   
     7     def detail(self):
     8         print self.name
     9         print self.age
    10   
    11 obj1 = Foo('wupeiqi', 18)
    12 obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18
    13   
    14 obj2 = Foo('alex', 73)
    15 obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

    综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

    req.obj是Auth对象 
    class Request(object):
        def __init__(self, obj):
            self.obj = obj
    
    
    class Auth(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    class APIView(object):
        def dispatch(self):
            self.f2()
    
        def f2(self):
            a = Auth('zrg', 18)
            req = Request(a)
            print(req.obj)
    
    
    obj = APIView()
    obj.dispatch()

    类似源码

    class Request(object):
        def __init__(self, obj):     #req a
            self.obj = obj           #req.a=a
    
        @property    #执行时不用加括号
        def user(self):               #第三步   req.obj.authenticate()=a.authenticate()
            return self.obj.authenticate()
    
    
    class Auth(object):
        def __init__(self, name, age):      #a,zrg,18
            self.name = name                #a.name=zrg,a.age=18
            self.age = age
    
        def authernticate(self):    #第四步   a.name
            # return True
            # 在源码里
            return self.name
    
    
    class APIView(object):
        def dispatch(self):         #传入对象自己obj
            self.f2()               #obj.f2()
    
        def f2(self):
            a = Auth('zrg', 18)     #第一步    实例化得到Auth对象a,把'zrg', 18封装进去  可以a.name  a.age   a.authernticate()
            req = Request(a)        #第二步    实例化得到Request对象 req   Request里面有个obj是Auth的对象a   可以req.obj  req.user
            print(req.user)         #第五步    对象里有什么就能点出来什么!
    
    obj = APIView()    #实例得到APIView的对象obj
    obj.dispatch()     #执行对象的dispatch方法

    CBV

    框架基于反射来实现--->根据method的不同执行不同的方法。

    反射的代码写在哪里?在View里面!

    在路由系统里面永远是URL对应一个函数,类的对应的是这样的:

    自己当前请求的类里面没有as_view方法,

    没有去父类找,找到了。并且返回了个view

    所以在路由那里执行as_view实际上是执行view方法,只不过这个函数里面有了cls,就是当前请求的类,类后面加括号,就是把这个类实例化

    所以相当于self = StudentsView(),实例化对象,指定dispatch方法,并有返回值,就是HttpResponse,render.....(因为视图函数要么返回。。。。)

    所以谁定义了dispatch,在定义的dispatch里面也有那些返回值。所以对CBV来说请求进来,执行里面的view函数可以忽略掉,直接执行dispatch。(不管什么请求进来都执行dispatch)

    class StudentsView(View):
        def dispatch(self, request, *args, **kwargs):
            # request.method #可以获得请求方法
            func = getattr(self,request.method.lower())     #去这个对象里面通过反射找到他不同的方法
            ret = func(request, *args, **kwargs)         #找到不同的方法可以执行一下,把它的参数都传进去。要有返回值,返回给客户
            return ret
            # return HttpResponse('父类的dispatch')
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('GET')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def putch(self, request, *args, **kwargs):
            return HttpResponse('PUTCH')

    但是以上代码不用自己写,父类(view)的的dispatch已经写好了

     http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    CBV原理跟流程:路由----->view方法------>dispatch方法(根据反射执行其他方法,get,post,put......)。

    如果自己当前类自己有dispatch方法,父类不会执行,但是如果想让父类执行dispatch方法怎么做?

    class StudentsView(View):
        def dispatch(self, request, *args, **kwargs):
            ret = super(StudentsView,self).dispatch(request, *args, **kwargs)   #父类的dispatch方法会反射不同的方式,ret就是HttpResponse(请求对象)
            return ret
            

    执行顺序是这样的,        

    class StudentsView(View):
        print('before')
        def dispatch(self, request, *args, **kwargs):
            print('before')
            ret = super(StudentsView,self).dispatch(request, *args, **kwargs)   #父类的dispatch方法会反射不同的方式,ret就是HttpResponse(请求对象)
            print('after')
            return ret
    
        def get(self, request, *args, **kwargs):
            return HttpResponse('GET')
    
        def post(self, request, *args, **kwargs):
            return HttpResponse('POST')
    
        def delete(self, request, *args, **kwargs):
            return HttpResponse('DELETE')
    
        def put(self, request, *args, **kwargs):
            return HttpResponse('PUT')
    
        def putch(self, request, *args, **kwargs):
            return HttpResponse('PUTCH')

    所有请求来了先执行before,在执行视图函数,在执行after。--->跟装饰器相似

    class StudentsView(View):def dispatch(self, request, *args, **kwargs):
            print('before')
            ret = super(StudentsView,self).dispatch(request, *args, **kwargs)   #父类的dispatch方法会反射不同的方式,ret就是HttpResponse(请求对象)
            print('after')
            return ret

     假如还有很多什么什么view,如果都需要先做before年最后做after,在下面写视图的时候,又得拷贝一遍。怎么办?

      写个基类,继承(多个类公用的功能,为了避免重复编写)。多继承左边优先。

    class MyBaseView(object):
        def dispatch(self, request, *args, **kwargs):
            print('before')
            ret = super(MyBaseView,self).dispatch(request, *args, **kwargs)   #父类的dispatch方法会反射不同的方式,ret就是HttpResponse(请求对象)
            print('after')
            return ret
    class StudentsView(MyBaseView,View): def get(self, request, *args, **kwargs):
         print('get方法')
    return HttpResponse('GET') def post(self, request, *args, **kwargs): return HttpResponse('POST') def delete(self, request, *args, **kwargs): return HttpResponse('DELETE') def put(self, request, *args, **kwargs): return HttpResponse('PUT') def putch(self, request, *args, **kwargs): return HttpResponse('PUTCH')

    super不是简单的只找父类,会根据super(MyBaseView,self)这个self对象整个的继承关系找到下一个继承对象里的方法。

    Django请求生命周期:

    请求进来先走wsgi--->中间件------>视图(FBV/CBV)----->如果是cbv进来走dispatch,然后反射找到试图函数返回。

    Django请求生命周期(包含rest framework框架):

    请求进来先走wsgi--->中间件------>视图(FBV/CBV)----->如果是cbv进来走dispatch,然后反射返回。---->重新写成Django的rest framework的dispatch了(添加了一部分功能)。

    ps:dispatch

                              

  • 相关阅读:
    php图片水印添加,压缩,剪切的封装类
    使用观察者模式处理异常信息
    php中的错误级别
    php 递归函数的三种实现方式
    php利用递归函数实现无限级分类
    利用http协议发布博客园博文评论
    结合php ob函数理解缓冲机制
    php 正则表达式捕获组与非捕获组
    php 利用socket发送GET,POST请求
    php mysqli扩展之预处理
  • 原文地址:https://www.cnblogs.com/zhangrenguo/p/10420202.html
Copyright © 2011-2022 走看看