drf概述

目录
一. REST

  1. 什么是编程?
  2. 什么是REST?
    二. 知识准备
  3. CBV(class based view)
  4. 类方法 classmethod和classonlymethod
  5. 反射、 isinstance()
    (1)getattr()
    (2)hasattr()
    (3)setattr()
    (4)isinstance()
  6. self定位
  7. http请求协议
  8. form表单的enctype属性中有三种请求协议
  9. JavaScript中的object(如: {name:‘alex‘} <==> json)的相互转换方式
    三. Django REST Framework ( DRF )
  10. 为什么要使用DRF?
  11. 什么时候使用DRF?
  12. DRF的使用
    DRF安装
  13. APIView
    (1)回顾CBV, 解读View源码
    (2)APIView
    四. 补充知识点
  14. 关于装饰器
  15. __dict__方法
  16. 对程序进行功能扩展的两种方式
  17. super()函数
    一. REST
  18. 什么是编程?
    数据结构和算法的结合
  19. 什么是REST?
    回顾曾经做过的图书管理系统, 我们是这样设计URL的:

   127.0.0.1:9001/books/
   127.0.0.1:9001/get_all_books/ 访问所有的数据

127.0.0.1:9001/books/{id}/
127.0.0.1:9001/books/{id}?method=get   访问单条数据

127.0.0.1:9001/books/add/
127.0.0.1:9001/books/?type=create   创建数据

127.0.0.1:9001/books/delete/

127.0.0.1:9001/books/update/   

以上定义的URL虽然也可以实现功能, 但是因个人习惯等的不同, 同一个功能会产生五花八门的URL, 而且响应回去的数据(包括错误提示等)格式也没有统一的规范, 这就造成了前后端交互上的困难.

由此产生了REST. REST下的URL唯一代表资源, http请求方式区分用户行为, 如下是符合REST规范的URL设计示例:

  url的设计规范:
    GET: 127.0.0.1:9001/books/ # 获取所有数据
    GET: 127.0.0.1:9001/books/{id} # 获取单条数据
    POST: 127.0.0.1:9001/books/ # 增加数据
    DELETE: 127.0.0.1:9001/books/{id} # 删除数据
    PUT: 127.0.0.1:9001/books/{id} # 修改数据
  数据响应规范:
    GET: 127.0.0.1:9001/books/ # 返回[{}, {}, {}]
    GET: 127.0.0.1:9001/books/{id} # 返回单条数据{}
    POST: 127.0.0.1:9001/books/ # 返回添加成功的数据{}
    DELETE: 127.0.0.1:9001/books/{id} # 返回空""
    PUT: 127.0.0.1:9001/books/{id} # 返回{} ,更新后完整的一条记录,注意并非一个字段
  错误处理:
{ "error": "error_message" }
REST是一种软件架构设计风格, 不是标准, 也不是技术实现, 它只是提供了一组设计原则和约束条件, 是目前最流行的API设计规范, 用于web数据接口的设计.

参考链接:

http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html

http://www.scienjus.com/my-restful-api-best-practices/

那么, 我们接下来要学习的Django REST Framework与REST有什么关系呢?

事实上, DRF(Django REST Framework)是一套基于Django开发的, 帮助我们更好的设计符合REST规范的web应用的一个Django App, 所以, 从本质上来讲, DRF是一个Django的App.

二. 知识准备
学习DRF之前, 首先回顾一下一个知识点:

  1. CBV(class based view)
    from django.views import View
    class LoginView(View):
    def get(self, request):
    pass
    def post(self, request):
    pass
  2. 类方法 classmethod和classonlymethod
    class Person(object):
    def init(self, name, age):
    self.name = name
    self.age = age

    # 注意: Person类加载的时候,会执行装饰器函数classmethod(sleeping),并将结果赋给sleeping
    @classmethod
    def sleeping(cls): # 相当于 sleeping = classmethod(sleeping)
    print("Tom is sleeping")

    @classonlymethod
    def shopping(cls):
    print("Tom is shopping")

Person.sleeping() # 类直接调用 类方法(用@classmethod装饰)
Person.Angel() # 类直接调用 方法(用@classonlymethod装饰)

Tom = Person(‘Tom‘, ‘19‘)
Tom.sleeping() # 对象可以直接调用 类方法
Tom.shopping() # baocuo,对象不能调用由@classonlymethod装饰的方法
总结:

@classmethod(python加的装饰器)装饰的方法可以被==对象和类==调用.
@classonlymethod(Django加的装饰器)只能被==类==调用.

  1. 反射、 isinstance()
    (1)getattr()
    描述: getattr()函数通过name这个字符串去object中找名字叫做name的属性, 如果找到了, 就返回这个对象的属性值, 如果找不到, 就返回default

语法:

getattr(object, name[, default])
参数:

object -- 对象
name -- 字符串, 对象的属性
default -- 默认返回值, 如果不提供参数, 在没有对应属性时, 将触发AttributeError
返回值: 返回对象属性

(2)hasattr()
描述: hasattr()函数用于判断对象是否包含对应的属性.

语法:

hasattr(object, name)
参数:

object -- 对象
name -- 字符串, 属性名
返回值: 如果对象object中存在一个名字叫做name的属性, 那么就返回True, 否则返回False.

(3)setattr()
描述: setsttr()函数对应函数getsttr(), 用于给对象object的name的属性重新设置值, 注意该属性name必须存在.

语法:

setattr(object, name, value)
参数:

object -- 对象
name -- 字符串, 对象属性
value -- 属性值
返回值: 无

(4)isinstance()
描述: isinstance()函数用来判断一个对象是否是一个已知的类型.

isinstence()与type()的区别:

-- type()不会认为子类是一种父类类型,不考虑继承关系.
-- isinstence()会认为子类是一种父类类型,考虑继承关系.
如果要判断两个类型是否相同推荐使用isinstence().
语法:

isinstence(object, classinfo)
参数:

object -- 实例对象
classinfo -- 可以是直接或间接类名, 基本类型或者由它们组成的元组
返回值: 如果对象的类型与参数二的类型(classinfo)相同则返回True, 否则返回False.

  1. self定位
    我们要明确, self指向的始终是==调用者==.
  2. http请求协议
    协议就是沟通双方约定俗成的规范, 也即是解析数据的规则
  3. form表单的enctype属性中有三种请求协议
    如果通过form表单提交用户数据, 可以使用form表单的enctype属性来定义数据编码协议, 该属性有三个值, 代表三种数据编码协议:

application/x-www-form-urlencoded: 该值使用&符号链接多个键值对, 键值对用等号拼接. 该值是enctype属性的默认值.
multipart/form-data: 上传文件, 图片时使用该值.
text/plain: 空格转换为+号.

  1. JavaScript中的object(如: {name:‘alex‘} <==> json)的相互转换方式
    JSON.stringify(data) ==> 相当于python的 json.dumps()
    JSON.parse(data) ==> 相当于python的 json.loads()
    三. Django REST Framework ( DRF )
  2. 为什么要使用DRF?
    DRF从本质上来讲, 它就是一个Django的App, 有了这样一个App, 我们就可以==更好的设计出符合RESTful规范的web应用==. 实际上, 即便没有DRF, 我们也能够自行设计出符合RESTful规范的web应用, 如下示例:

from django.shortcuts import HttpResponse
from django.views import View
from * import models
import json
class CourseView(View):
def get(self, request):
course_list = list()

    for course in models.Course.objects.all():
        course = {
            'course_name': course.course_name,
            'description': course.description,
        }
        course_list.append(course)

    return HttpResponse(json.dumps(course_list, ensure_ascii=False))

在上面的代码中, 我们获取所有的课程数据, 并且根据REST规范, 将所有资源通过列表返回给用户, 可见, 就算没有DRF, 我们也能够设计出符合RESTful规范的接口, 甚至是整个App应用. 但是, 如果所有的接口都自定义, 难免会出现重复代码, 为了提高工作效率, 我们建议使用优秀的工具, DRF就是这样一个优秀的工具, 另外, 它不仅能够帮助我们快速的设计出符合RESTful规范的接口, 还提供了诸如 认证 , 权限 等等其他强大的功能.

  1. 什么时候使用DRF?
    RESTful 是目前最流行的API设计规范, 如果使用Django开发你的web应用, 那么请尽量使用DRF, 如果使用的是Flask, 则可以使用Flask-RESTful.
  2. DRF的使用
    DRF官方文档

DRF安装

安装django

pip install django

安装djangorestframework

pip install djangorestframework
安装完成以后, 我们就可以开始使用DRF框架来实现我们的web应用了. 该框架包含以下知识点:

  - APIView
  - 解析器组件
  - 序列化组件
  - 视图组件
  - 认证组件
  - 权限组件
  - 频率控制组件
  - 分页组件
  - 相应器组件
  - url控制

  1. APIView
    介绍DRF, 必须介绍APIView, 它是重中之重, 是下面所有组件的基础, 因为==所有的请求都是通过APIView来分发的==. 那么它究竟是如何来分发请求的呢? 想要弄明白这个问题, 就必须解读它的源码, 而想要解读DRF的APIView源码, 就必须首先弄清楚django中views.View类的源码, 为什么使用了视图函数类调用as_view()之后, 请求就可以被不同的函数处理了呢?

(1)回顾CBV, 解读View源码

urls.py中代码如下:

from django.urls import path, include, re_path
from classbasedView import views
urlpatterns = [
re_path(‘login/$‘, views.LoginView.as_view())]

views.py中代码如下:

from django.views import View
class LoginView(View):
def get(self, request):
pass
def post(self, request):
pass
以上代码执行流程如下(源码解读):

(1)启动django项目, 即执行了python manage.py runserver 127.0.0.1:8000之后
(2)开始加载settings.py配置文件
读取models.py
加载views.py
加载urls.py, 执行as_view(): views.LoginView.as_view()
(3)由于LoginView中没有as_view, 因此执行父类View中的as_view方法, 父类View的相关源码如下:
class View:
http_method_names = [‘get‘, ‘post‘, ‘put‘, ...]
def init(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)

@classonlymethod
def as_view(cls, **initkwargs):
    for key in initkwargs:
        ...
    def view(request, * args, **kwargs):
        """
        实例化一个对象,对象名称为self,self是cls的对象,谁调用了as_view,cls就是谁(当前调用as_view的是LoginView),所以,此时的self就是LoginView实例化对象.
        """
        self = cls(**initkwargs)
        if hassttr(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 = initwargs

    update_wrapper(view, cls, updated=())
    update_wrapper(view, cls.dispatch, assigned=())
    return view

def dispatch(self, request, *args, **kwargs):
    if request.method.lower() in self.http_method_name:
        # 通过getattr找到的属性,已和对象绑定,访问时不需要再指明对象了
        # 即不需要再: self.handler, 直接handler()执行
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
    return handler(request, *args, **kwargs)            

上面的源码中可以看出as_view是一个类方法, 并且方法中定义了view函数, 且as_view将view函数返回, 此时url与某一个函数的对应关系建立, 并开始等待用户请求.

(4)当用户发来请求(如get请求), 开始执行url对应的view函数, 并传入request对象, View类中view函数的执行结果是返回self.dispatch(request, *args, **kwargs)的执行结果, 这里的self是指LoginView的实例化对象. 由于LoginView中没有dispatch方法, 所以去执行父类APIView中的dispatch方法, 同样, APIView类中的dispatch函数中也是通过反射找到self(此时self指LoginView的实例化对象)所属类(即LoginView)中的get方法, dispatch函数中的handler(request, *args, **kwargs)表示执行LoginView类中的get方法, 其执行结果就是dispatch的执行结果, 也就是请求url对应view函数的执行结果, 最后将结果返回给用户.
(2)APIView
使用:

views.py中代码:

from rest_framework.views import APIView # 引入APIView
class LoginView(APIView): # 继承APIView
def get(self, request):
pass
def post(self, request):
pass

urls.py中代码:

from django.urls import path, include, re_path
from classbasedView import views
urlspatterns = [
re_path(‘login/$‘, views.LoginView.as_view())]
源码解读:

(1)启动django项目: python manage.py runserver 127.0.0.1:8000
(2)开始加载settings.py文件
(3)读取models.py文件
(4)加载views.py文件
(5)加载urls.py文件, 执行as_view(): views.LoginView.as_view()
(6)由于LoginView中没有as_view, 因此去执行父类APIView中的as_view方法, 父类APIView的相关源码如下:
class APIView(View):
...
# api_settings是APISettings类的实例化对象
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
...
settings = api_setings
schema = DefaultSchema()

@classmethod
def as_view(cls, **initkwargs):     # cls指LoginView
    if isinstence(getattr(cls, 'queryset', None), models.query.Queryset):
        ...
    # 下面一句表示去执行APIView父类(即View类)中的as_view方法
    view = super(APIView, cls).as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs
    return csrf_exempt(view)

def dispatch(self, request, *args, **kwargs):
    ...
    request = self.initialize_request(request, *args, **kwargs)
    ...
    try:
        self.initial(request, *args, **kwargs)
        if request.method.lower() in self.http_method_name:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        response = self.handler(request, *args, **kwargs)
    except Exception as exc:
        response = self.handle_exception(exc)

    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

参考上面的View源码解读, 我们已经知道View中的as_view方法返回view函数, 此时url与view对应关系已经建立, 等待用户请求.

(7)当用户发来请求(如get请求), 开始执行url对应的view函数, 并传入request对象, View类中view函数的执行结果是返回self.dispatch(request, *args, **kwargs)的执行结果, 这里的self是指LoginView的实例化对象, LoginView中没有dispatch方法, 所以去执行父类APIView中的dispatch方法, 同样, APIview类中的dispatch函数中也是通过反射找到self(此时self指LoginView的实例对象)所属类(即LoginView)中的get方法, dispatch函数中的handler(request, *args, **kwargs)表示执行LoginView类中的get方法, 其执行结果就是dispatch的执行结果, 也就是请求url对应view函数的执行结果, 最后将结果返回给用户.
四. 补充知识点

  1. 关于装饰器
    若类中有装饰器函数, 那么当类加载的时候, 装饰器函数就会执行, 如下代码:

class Person(object):
@classmethod # 相当于 sleeping = classmethod(sleeping)
def sleeping(cls):
print(‘Tom is sleeping‘)

print(sleeping)
# 加载类时执行,结果是:<classmethod object at 0x000001F2C29C8198>

注意: 类中直接print会执行打印并输出结果, 而函数只有调用时才会执行, 如下所示:

def func():
print(‘Hello World!‘)

函数func 加载 不会执行打印

而只有当我们调用 func() 才会执行打印

  1. __dict__方法
    class Person(object):
    def init(self, name, age):
    self.name = name
    self.age = age

    def sing(self):
    print(‘I am singing!‘)

p1 = Person(‘alex‘, 18)
print(p1.__dict__) # {‘name‘:‘alex‘, ‘age‘:18}
print(Person.__dict__)
‘‘‘
{‘module‘: ‘main‘,
init‘: <function Person.__init__ at 0x0000021E1A46A8C8>,
‘sing‘: <function Person.sing at 0x0000021E1A46A950>,
dict‘: <attribute ‘dict‘ of ‘Person‘ objects>,
weakref‘: <attribute ‘weakref‘ of ‘Person‘ objects>,
doc‘: None}
‘‘‘
总结:

对象.__dict__ 返回对象的所有成员字典;
类.__dict__ 返回类的所有成员字典;
我们可以通过 对象.name 取出成员, 字典没有这种取值方式, 使用 对象.name 的本质是执行类中的 getitem 方法.

  1. 对程序进行功能扩展的两种方式
    现在有如下两种需求:

需求一: 计算下面add函数的执行时间(不重写add函数的前提下)

def add(x, y):
return x + y

解决方式: 装饰器

def outer(func):
def inner(*args, **kwargs):
import time
start_time = time.time()
ret = func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return inner

@outer
def add(x, y):
return x + y

需求二: 扩展类中函数的功能(在不重写Father类的前提下)

class Father(object):
def show(self):
print(‘father show is excuted!‘)

father = Father()
father.show()

解决方式: 重新写一个类, 继承Father类, 重写show()方法, 用super()调用

class Son(Father):
def show(self):
print(‘son show is excuted!‘)
super().show()

son = Son()
son.show()
总结:

面向过程的方式对程序功能进行扩展:
装饰器
面向对象的方式对程序功能进行扩展:
类的继承
方法重写
super()执行父类的方法

  1. super()函数
    描述: super()函数是用于调用父类(超类)的一个方法. super是用来解决多重继承问题, 直接用类名调用父类方法在使用单继承的时候没有问题, 但是如果使用多继承, 会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题.

MRO就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表.

语法:

super(type[, object-or-type])
参数:

type -- 类
object-or-type -- 类, 一般是self
返回值: 无

==注意==: Python3.x 和 Python2.x的一个区别是: Pyhton3 可以直接使用 super().xxx 代替 super(Class, self).xxx.

Python3.x与Python2.x中super()的用法对比:

Python3.x实例:

class A:
pass
class B(A):
def add(self, x):
super().add(x)

Python2.x实例:

class A(object): # Python2.x记得要继承object
pass
class B(A):
def add(x):
super(B, self).add(x)
实例说明:

class FooParent(object):
def init(self):
self.parent = ‘I am the parent!‘
print(‘Parent‘)

def bar(self, message):
    print('%s from Parent!' % message)
    

class FooChild(FooParent):
def init(self):
‘‘‘
以super(B, self)的格式作为参照,
super(FooChild, self)首先找到FooChild的父类(即FooParent),
然后把类B(即super()的第一个参数)的对象FooChild转换为FooParent的对象
‘‘‘
super(FooChild, self).__init__()
print(‘Child‘)

def bar(self, message):
    super(FooChild, self).bar(message)
    print('Child bar function!')
    print(self.parent)
    

if name == ‘main‘:
fooChild = FooChild()
fooChild.bar(‘HelloWorld‘)

执行结果:

Parent

Child

HelloWorld from Parent!

Child bar fuction!

I am the parent!

原文地址:https://www.cnblogs.com/whnbky/p/12004054.html

时间: 2024-10-14 16:37:06

drf概述的相关文章

一: DRF web应用框架基础

---恢复内容开始--- 一: web 应用模式(有两种) 1: 前后端不分离(前端从后端直接获取数据) 2: 前后端分离 二: api 接口 原因一: 为了在团队内部形成共识.防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少双方之间的合作成本. 目前市面上大部分公司开发人员使用的接口服务架构主要有:restful.rpc. 1: rpc: 翻译成中文:远程过程调用[远程服务调用]. post请求 action=get_

DRF 缓存解决方案 drf-extensions / redis

drf-extensions 概述 drf-extensions组件内部提供了 DRF  的本地内存方式的缓存方式 本地内存方式缓存在项目重启后则会消失 官方点击 这里 安装 pip3 install drf-extensions or from github pip3 install https://github.com/chibisov/drf-extensions/archive/master.zip 导入 from rest_framework_extensions.cache.mixi

第一课 MongoDB 概述与安装

1.课程大纲 本次课主要介绍 MongoDB 背景知识和 MongoDB 的安装与配置,让大家对 MongoDB 有一个初认识. 其基本的知识点包含: NoSQL数据库概述 MongoDB 数据库简单介绍 Linux 下安装 MongoDB 数据库 Mac 和 Windows 下安装 MongoDB 数据库 2.课程简单介绍 MongoDB是由MongoDB.inc研发的一款NoSQL类型的文档型数据库,MonogoDB名字来源于英文单词humongous,这个单词的意思是巨大无比.暗喻Mong

java面向对象:面向对象的思想和概述

1:面向对象思想 面向对象是基于面向过程的编程思想. 面向过程:强调的是每一个功能的步骤 面向对象:强调的是对象,然后由对象去调用功能 2:面向对象的思想特点 A:是一种更符合我们思想习惯的思想 B:可以将复杂的事情简单化 C:将我们从执行者变成了指挥者 开发,设计,特征 面向对象开发 就是不断的创建对象,使用对象,指挥对象做事情. 面向对象设计 其实就是在管理和维护对象之间的关系. 面向对象特征 封装(encapsulation) 继承(inheritance) 多态(polymorphism

java基础总结——概述

  一.java语言概述 来自维基百科 https://zh.wikipedia.org/wiki/Java Java是一种计算机编程语言,拥有跨平台.面向对象.泛型编程的特性,广泛应用于企业级Web应用开发和移动应用开发. 任职于太阳微系统的詹姆斯·高斯林等人于1990年代初开发Java语言的雏形,最初被命名为Oak,目标设置在家用电器等小型系统的程序语言,应用在电视机.电话.闹钟.烤面包机等家用电器的控制和通信.由于这些智能化家电的市场需求没有预期的高,Sun公司放弃了该项计划.随着1990

译-BMC Remedy Action Request System权限控制概述

原文链接:Access control overview 说明: BMC Remedy Action Request System是BMC ITSM产品平台,简称AR 或者Remedy,可实现基于ITIL标准的整个IT管理流程的实施定制.该平台可实现多种权限级别的管理,包括人员.组.角色,以及表.字段.行级别等.本文可以用作其他对权限要求比较精细的系统参考. 为了便于理解,部分名词翻译如下: Server:服务器Form (or table):表单Field (or column):字段Acti

Aircrack-ng: (1) 概述

作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 目录 一.概述 二.工具与命令介绍 Linux命令 (1) ifconfig (2) macchanger (3) iwconfig (4) iwlist Aircrack-ng 工具 (1) airmon-ng (2) airodump-ng (3) aireplay-ng (4) aircrack-ng 其他Aircrack-ng工具 一.概述 Aircrack-ng是一款用于破解无线

NHibernate框架与BLL+DAL+Model+Controller+UI 多层架构十分相似--『Spring.NET+NHibernate+泛型』概述、知识准备及介绍(一)

原文://http://blog.csdn.net/wb09100310/article/details/47271555 1. 概述 搭建了Spring.NET+NHibernate的一个数据查询系统.之前没用过这两个框架,也算是先学现买,在做完设计之 后花了一周搭建成功了.其中,还加上了我的一些改进思想,把DAO和BLL之中相似且常用的增删改查通过泛型T抽象到了DAO和BLL的父类中,其DAO 和BLL子类只需继承父类就拥有了这些方法.和之前的一个数据库表(视图)对应一个实体,一个实体对应一

排序算法--概述和参考

1 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 2 参考 http://blog.csdn.net/hguisu/article/details/77