一 . 知识点回顾

1 . 混入类 , 多继承

class Animal(object):
def eat(self):
print("Eat") def walk(self):
print("Walk") def sleep(self):
print("Sleep") def run(self):
print("Run") def flying(self):
print("Flying") def wangwang(self):
print("Wangwang") def miao(self):
print() class Dog(Animal):pass class Cat(Animal):pass class Bird(Animal):pass

可以看到,Dog类继承了Animal类,但是Dog并没有飞行和喵的功能,所以,如果直接继承Animal会有一些问题,请同学们思考,如何解决这个问题呢?

好了,其实我们有多中方式可以解决这个问题,比如:

class Animal(object):
def eat(self):
print("Eat") def walk(self):
print("Walk") def sleep(self):
print("Sleep") def run(self):
print("Run") class Flying(object):
def flying(self):
print("Flying") class WangWang(object):
def wangwang(self):
print("Wangwang") class Miao(object):
def miao(self):
print() class Dog(Animal, WangWang):pass class Cat(Animal, Miao):pass class Bird(Animal, Flying):pass

我们将不同的功能封装到了独立的类中,然后采用一种Mixin(混合类)的方式,其实也就是多继承,来解决这个问题,这在Python中是比较常见的解决方式,比如socketserver模块就用到了这种方式,当我们需要线程的时候,可以继承线程类,当我们需要进程的时候,可以继承进程类。

2 . 函数的参数

def func(a, b, c=1, *args, **kwargs):
print(a, b, c, args, kwargs) func(1, 2, 3, 4, 5) # 1, 2, 3, (4, 5) 所有未被匹配到的非key=value型的参数都会被*args接收
func(b=1, a=1, c=2, 4, 5) # 报错,位置参数不能在关键字参数之后
func(4, 5, c=3, {"name": "pizza"}) # 报错,位置参数不能在关键字参数之后,字典不是关键字参数
func({"name": "pizza"}, 1, 2) # {'name': 'pizza'} 1 2 () {}
func(1, 2, 3, 4, 5, d=1, e=2) # 1 2 3 (4, 5) {'d': 1, 'e': 2} 未被匹配到的关键字参数被传递给kwargs

二 . 序列化组件(get/put/delete接口设计)

  基于上篇的表结构,通过序列化组件的 ModelSerializer 设计如下三个接口 :

GET       127.0.0.1:8000/books/{id}    # 获取一条数据,返回值:{}
PUT 127.0.0.1:8000/books/{id} # 修改数据,返回值:{}
DELETE 127.0.0.1:8000/books/{id} # 删除数据,返回空

urls.py 文件

from django.urls import path, re_path
from serializer import views
urlpatterns = [
re_path('books/(\d+)/$', views.BookFilterView.as_view())
]

Views,py 文件 :

class BookFilterView(APIView):
def get(self, request, nid):
book_obj = Book.objects.get(pk=nid)
serialized_data = BookSerializer(book_obj, many=False)
return Response(serialized_data.data) def put(self, request, nid):
book_obj = Book.objects.get(pk=nid)
verified_data = BookSerializer(data=request.data, instance=book_obj, many=False)
if verified_data.is_valid():
verified_data.save()
return Response(verified_data.data)
else:
return Response(verified_data.errors) def delete(self, request, nid):
Book.objects.get(pk=nid).delete()
return Response()

PUT接口逻辑的设计,分为如下几个步骤:

  • url设计:re_path(r’books/(\d+)/$’, views.BookFilterView.as_view())
  • 视图类:重新定义一个视图类
  • put方法:在视图类中定义一个put方法
  • 序列化:在序列化的过程中,需要传入当前修改的数据行,参数名为instance
  • 序列化类:不需要修改
  • url路径:请求时,发送的url必须与urls.py中定义的url完全匹配

所以 , 加上上一篇的get和post接口,我们现在5个常用接口设计完成了,接口如下 :

class BookView(APIView):
def get(self, request):
origin_books = Book.objects.all()
serialized_books = BookSerializer(origin_books, many=True) return Response(serialized_books.data) def post(self, request):
verified_data = BookSerializer(data=request.data) if verified_data.is_valid():
book = verified_data.save()
return Response(verified_data.data)
else:
return Response(verified_data.errors) class BookFilterView(APIView):
def get(self, request, nid):
book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(book_obj, many=False) return Response(serialized_data.data) def delete(self, request, nid):
book_obj = Book.objects.get(pk=nid).delete() return Response("") def put(self, request, nid):
book_obj = Book.objects.get(pk=nid) serialized_data = BookSerializer(data=request.data, instance=book_obj) if serialized_data.is_valid():
serialized_data.save()
return Response(serialized_data.data)
else:
return Response(serialized_data.errors)

两个视图类的接口逻辑

三 . 视图组件

  前面的介绍中,我们已经通过序列化组件设计除了符合REST规范的五个常用接口,现在假设,我们有多个数据接口,比如(Book,Author,Publish...)等数据表都需要定义类似的接口,可以预见,我们需要重复定义类似上面的五个接口,这种方式将会导致大量的重复代码,显然,我们的程序还有很多需要优化的地方,那么,如果是你,将会如何进行优化呢?

  这个时候,就需要我们的视图组件进行优化了!!!!!!

  视图组件是用来优化接口逻辑的

视图组件的使用

1 . 使用视图组件的 mixin 进行接口逻辑优化 :

urls.py 代码 :

from django.urls import re_path
from serializer import views urlpatterns = [
re_path('books/$', views.BookView.as_view()),
re_path('books/(?P<pk>\d+)/$', views.BookFilterView.as_view()),
]

视图 views.py :

from rest_framework.mixins import (
ListModelMixin,
CreateModelMixin,
DestroyModelMixin,
UpdateModelMixin,
RetrieveModelMixin
)
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
# 导入序列化类
from .app_serializers import BookSerializer
from .models import Book, Publish, Author class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
# queryset和serializer_class是固定写法
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs) def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs) class BookFilterView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs) def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs) def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)

  注意:单条数据操作的url有变化,因为我们在视图中,统一传的都是queryset,所以,需要通过传入一个名为pk的命名参数,告诉视图组件,用户需要操作的具体数据。

2 . 使用视图组件的 genericview 进行接口逻辑优化

  上面的代码看似已经优化的非常完美了,但是,在一个对性能要求极高的项目里面,我们的程序还可以继续优化,不断优化程序是每个程序员必备的技能,也是帮助我们成长的重要手段。同样的思路,同样的方法,我们可以将多个接口封装到一个功能类中,如下代码:

views.py :

from rest_framework import generics

from .app_serializers import BookSerializer
from .models import Book, Publish, Author class BookView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer class BookFilterView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer

3 . 使用视图组件的 viewset 进行接口逻辑优化

  上面的代码已经看似非常完美了,但是,你有没有发现还有重复代码,该如何改进呢?使用viewset可以进一步优化,如下:

urls.py文件(注意跟之前有什么不同)

from django.urls import re_path
from serializer import views urlpatterns = [
re_path('books/$', views.BookView.as_view({
'get': 'list',
'post': 'create'
})),
re_path('books/(?P<pk>\d+)/$', views.BookView.as_view({
'get': 'retrieve',
'put': 'update',
'delete': 'destroy'
}))

视图 views.py :

from rest_framework.viewsets import ModelViewSet
from .app_serializers import BookSerializer
from .models import Book, Publish, Author class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer

  使用方式是不是很简单,接下来去看以下源码都为我们做了什么吧!其实整个viewset优化方案最重要的地方就是urls.py中传入了参数,然后对参数进行映射关系绑定。

viewset 源码剖析

  • Django程序启动,开始初始化,读取urls.py, 读取settings, 读取视图类
  • 执行as_views(), BookView没有,需要到父类(ModelViewSet)中找
  • ModelViewSet继承了mixins的几个ModelMixin和GenericViewSet,显然ModelMixin也没有,只有GenericViewSet中有
  • GenericViewSet没有任何代码,只继承了ViewSetMixin和generics.GenericAPIView(这个我们已经认识了)
  • 继续去ViewSetMixin中查找,找到了as_view类方法,在重新封装view函数的过程中,有一个self.action_map = actions
  • 这个actions就是我们给as_view()传递的参数
  • 绑定url和视图函数(actions)之间的映射关系
  • 等待用户请求
  • 接收到用户请求,根据url找到视图函数
  • 执行视图函数的dispatch方法(因为视图函数的返回值是:return self.dispatch()
  • dispatch分发请求,查找到视图类的五个方法中的某个
  • 开始执行,比如post请求,返回:self.create(),视图类本身没有,则会到父类中查找
  • 最后在CreateModelMixin中查找
  • 执行create()方法,获取queryset和serializer_class
  • 返回数据

这就是viewset的优化方案,整个优化方案最重要的地方就是urls.py中我们传入的参数,然后对参数进行映射关系绑定。

序列化组件(get/put/delete接口设计),视图优化组件的更多相关文章

  1. DRF(3) - 序列化组件(GET/PUT/DELETE接口设计)、视图优化组件

    一.序列化组件 基于上篇随笔的表结构,通过序列化组件的ModelSerializer设计如下三个接口: GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{} PU ...

  2. DRF - 序列化组件(GET/PUT/DELETE接口设计)、视图优化组件

    一.序列化组件 基于上篇随笔的表结构 , 通过序列化组件的ModelSerializer设计如下三个接口 : GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{} ...

  3. Restful 3 -- 序列化组件(GET/PUT/DELETE接口设计)、视图优化组件

    一.序列化组件 基于上篇随笔的表结构,通过序列化组件的ModelSerializer设计如下三个接口: GET 127.0.0.1:8000/books/{id} # 获取一条数据,返回值:{} PU ...

  4. django rest framework 解析器组件 接口设计,视图组件 (2)

    1. 使用视图组件进行接口优化 1.1 使用视图组件的mixin进行接口逻辑优化 - 导入mixin from rest_framework.mixinx import ( ListModelMix, ...

  5. django rest framework 解析器组件 接口设计,视图组件 (1)

    一.解析器组件 -解析器组件是用来解析用户请求数据的(application/json), content-type 将客户端发来的json数据进行解析 -必须适应APIView -request.d ...

  6. DRF-->1 序列化组件的使用和接口设计---get

    定义序列化器(本质就是一个类),一般包括模型类的字段,有自己的字段类型规则.实现了序列化器后,就可以创建序列化对象以及查询集进行序列化操作,通过序列化对象.data来获取数据(不用自己构造字典,再返回 ...

  7. DRF-->2序列化组件的使用和接口设计--get,post,put,delete&优化组件

    !!!!! !!!!! 记住这个图 !!!!! 上篇博客说道DRF序列化组件的get,只是简单的举一个实例,然而在现实生活中我们前后端进行交互的时候更多的用到了Json数据格式,这也就是说前后端交互的 ...

  8. DRF(2) - 解析器,序列化组件使用(GET/POST接口设计)

    一.DRF - 解析器 1.解析器的引出 我们知道,浏览器可以向django服务器发送json格式的数据,此时,django不会帮我们进行解析,只是将发送的原数据保存在request.body中,只有 ...

  9. Restful 2 --DRF解析器,序列化组件使用(GET/POST接口设计)

    一.DRF - 解析器 1.解析器的引出 我们知道,浏览器可以向django服务器发送json格式的数据,此时,django不会帮我们进行解析,只是将发送的原数据保存在request.body中,只有 ...

随机推荐

  1. Java数组去掉反复的方法集

    经经常使用到,有时候不仅仅是简单的基本类型,那种能够用set集合去重,好多时间用到的是我们自己定义的类型,以下举个样例(我这儿就那int举例了): 方法一. 这样的类似与选择排序算法,首先我们取i值, ...

  2. AudioSession/AudioCaptureSession的分析与使用

    这个是AudioSession的结构图: 前一个部分已经介绍了AVFoundation对音频录制.播放的一种方法,以下再介绍第二种: AVCaptureSession 用这个类的长处在什么地方呢? ( ...

  3. UNP学习笔记(第二十六章 线程)

    线程有时称为轻权进程(lightweight process) 同一进程内的所有线程共享相同的全局内存.这使得线程之间易于共享信息,然后这样也会带来同步的问题 同一进程内的所有线程处理共享全局变量外还 ...

  4. Java使用笔记之stream和sorted使用

    //对象类型stream排序List<User> users = new ArrayList<User>(){ { add(new User("a", &q ...

  5. 朴素贝叶斯分类算法-----java

    1.贝叶斯分类的基础--贝叶斯定理 已知某条件概率.怎样得到两个事件交换后的概率,也就是在已知P(A|B)的情况下怎样求得P(B|A). 这里先解释什么是条件概率: 表示事件B已经发生的前提下,事件A ...

  6. 详细解析用Squid实现反向代理的方法

    代理服务器是使 用非常普遍的一种将局域网主机联入互联网的一种方式,使用代理上网可以节约紧缺的IP地址资源,而且可以阻断外部主机对内部主机的访问,使内部网主机免受 外部网主机的攻击.但是,如果想让互联网 ...

  7. 手把手实现andriod应用增量升级

    近期研究了android应用增量升级的应用.当中用到了android NDK编程,先说下为什么要使用增量升级.当我们的应用达到一定大小的时候,比方眼下有30M.假设新版本号35M仅仅是添加了几个功能, ...

  8. .NET C# Json序列化与反序列化——Newtonsoft.Json学习笔记

    Newtonsoft.Json,一款.NET中开源的Json序列化和反序列化类库(介绍及下载地址:http://json.codeplex.com/). /// <summary>    ...

  9. ASP.NET MVC路径引用总结

    1.关于路径: (1)绝对路径 包含站点路径的路径:<a href=”http://www.baidu.com/about.jpg”>百度</a> 站点改变路径失效: (2)相 ...

  10. Double类parseDouble()和valueOf()方法的区别

    数字类型的String字符串转换为浮点数通常采用parseDouble()和valueOf()方法, 两者主要是存在以下两点区别. 区别一:参数区别Double.parseDouble(java.la ...