Days
- 00. 简介
- 01. 初识 Python
- 02. 语言元素
- 03. 分支结构
- 04. 循环结构
- 05. 构造程序逻辑
- 06. 函数和模块的使用
- 07. 字符串和常用数据结构
- 08. 面向对象编程基础
- 09. 面向对象进阶
- 10. 图形用户界面和游戏开发
- 11. 文件和异常
- 12. 字符串和正则表达式
- 13. 进程和线程
- 14. 网络编程入门和网络应用开发
- 15. 图像和办公文档处理
- 16 20. Python 语言进阶
- 21 30. Web 前端概述
- 31 35. 玩转 Linux 操作系统
- 36. 关系型数据库和 MySQL 概述
- 37. SQL 详解之 DDL
- 38. SQL 详解之 DML
- 39. SQL 详解之 DQL
- 40. SQL 详解之 DCL
- 41. MySQL 新特性
- 42. 视图、函数和过程
- 43. 索引
- 44. Python接入MySQL数据库
- 45. 大数据平台和HiveSQL
- 46. Django快速上手
- 47. 深入模型
- 48. 静态资源和 Ajax 请求
- 49. Cookie 和 Session
- 50. 制作报表
- 51. 日志和调试工具栏
- 52. 中间件的应用
- 53. 前后端分离开发入门
- 54. RESTful 架构和 DRF 入门
- 55. RESTful 架构和 DRF 进阶
- 56. 使用缓存
- 57. 接入三方平台
- 58. 异步任务和定时任务
- 59. 单元测试
- 60. 项目上线
- 61. 网络数据采集概述
- 62. 用 Python 获取网络资源 1
- 62. 用 Python 解析 HTML 页面 2
- 63. Python 中的并发编程 1
- 63. Python 中的并发编程 2
- 63. Python 中的并发编程 3
- 63. 并发编程在爬虫中的应用
- 64. 使用 Selenium 抓取网页动态内容
- 65. 爬虫框架 Scrapy 简介
- 66. 数据分析概述
- 67. 环境准备
- 68. NumPy 的应用 1
- 69. NumPy 的应用 2
- 70. NumPy 的应用 3
- 71. NumPy 的应用 4
- 72. 深入浅出 pandas 1
- 73. 深入浅出 pandas 2
- 74. 深入浅出 pandas 3
- 75. 深入浅出 pandas 4
- 76. 深入浅出 pandas 5
- 77. 深入浅出 pandas 6
- 78. 数据可视化 1
- 79. 数据可视化 2
- 80. 数据可视化 3
- 81. 人工智能和机器学习概述
- 82. k 最近邻分类
- 83. 决策树
- 83. 推荐系统实战 1
- 84. 贝叶斯分类
- 85. 支持向量机
- 86. K 均值聚类
- 87. 回归分析
- 88. 深度学习入门
- 89. PyTorch 概述
- 90. PyTorch 实战
- 91. 团队项目开发的问题和解决方案
- 92. Docker 容器技术详解
- 93. MySQL 性能优化
- 94. 网络 API 接口设计
- 95. 使用 Django 开发商业项目
- 96. 软件测试和自动化测试
- 97. 电商网站技术要点剖析
- 98. 项目部署上线和性能调优
- 99. 面试中的公共问题
- 100. Python 面试题实录
公开课
番外篇
55. RESTful 架构和 DRF 进阶
除了上一节讲到的方法,使用DRF创建REST风格的数据接口也可以通过CBV(基于类的视图)的方式。使用CBV创建数据接口的特点是代码简单,开发效率高,但是没有FBV(基于函数的视图)灵活,因为使用FBV的方式,数据接口对应的视图函数执行什么样的代码以及返回什么的数据是高度可定制的。下面我们以定制学科的数据接口为例,讲解通过CBV方式定制数据接口的具体做法。
使用CBV
继承APIView的子类
修改之前项目中的polls/views.py
,去掉show_subjects
视图函数,添加一个名为SubjectView
的类,该类继承自ListAPIView
,ListAPIView
能接收GET请求,它封装了获取数据列表并返回JSON数据的get
方法。ListAPIView
是APIView
的子类,APIView
还有很多的子类,例如CreateAPIView
可以支持POST请求,UpdateAPIView
可以支持PUT和PATCH请求,DestoryAPIView
可以支持DELETE请求。SubjectView
的代码如下所示。
from rest_framework.generics import ListAPIView
class SubjectView(ListAPIView):
# 通过queryset指定如何获取学科数据
queryset = Subject.objects.all()
# 通过serializer_class指定如何序列化学科数据
serializer_class = SubjectSerializer
刚才说过,由于SubjectView
的父类ListAPIView
已经实现了get
方法来处理获取学科列表的GET请求,所以我们只需要声明如何获取学科数据以及如何序列化学科数据,前者用queryset
属性指定,后者用serializer_class
属性指定。要使用上面的SubjectView
,需要修改urls.py
文件,如下所示。
urlpatterns = [
path('api/subjects/', SubjectView.as_view()),
]
很显然,上面的做法较之之前讲到的FBV要简单很多。
继承ModelViewSet
如果学科对应的数据接口需要支持GET、POST、PUT、PATCH、DELETE请求来支持对学科资源的获取、新增、更新、删除操作,更为简单的做法是继承ModelViewSet
来编写学科视图类。再次修改polls/views.py
文件,去掉SubjectView
类,添加一个名为SubjectViewSet
的类,代码如下所示。
from rest_framework.viewsets import ModelViewSet
class SubjectViewSet(ModelViewSet):
queryset = Subject.objects.all()
serializer_class = SubjectSerializer
通过查看ModelViewSet
类的源代码可以发现,该类共有6个父类,其中前5个父类分别实现对POST(新增学科)、GET(获取指定学科)、PUT/PATCH(更新学科)、DELETE(删除学科)和GET(获取学科列表)操作的支持,对应的方法分别是create
、retrieve
、update
、destroy
和list
。由于ModelViewSet
的父类中已经实现了这些方法,所以我们几乎没有编写任何代码就完成了学科数据全套接口的开发,我们要做的仅仅是指出如何获取到数据(通过queryset
属性指定)以及如何序列化数据(通过serializer_class
属性指定),这一点跟上面继承APIView
的子类做法是一致的。
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
要使用上面的SubjectViewSet
,需要在urls.py
文件中进行URL映射。由于ModelViewSet
相当于是多个视图函数的汇总,所以不同于之前映射URL的方式,我们需要先创建一个路由器并通过它注册SubjectViewSet
,然后将注册成功后生成的URL一并添加到urlspattern
列表中,代码如下所示。
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('api/subjects', SubjectViewSet)
urlpatterns += router.urls
除了ModelViewSet
类外,DRF还提供了一个名为ReadOnlyModelViewSet
的类,从名字上就可以看出,该类是只读视图的集合,也就意味着,继承该类定制的数据接口只能支持GET请求,也就是获取单个资源和资源列表的请求。
数据分页
在使用GET请求获取资源列表时,我们通常不会一次性的加载所有的数据,除非数据量真的很小。大多数获取资源列表的操作都支持数据分页展示,也就说我们可以通过指定页码(或类似于页码的标识)和页面大小(一次加载多少条数据)来获取不同的数据。我们可以通过对QuerySet
对象的切片操作来实现分页,也可以利用Django框架封装的Paginator
和Page
对象来实现分页。使用DRF时,可以在Django配置文件中修改REST_FRAMEWORK
并配置默认的分页类和页面大小来实现分页,如下所示。
REST_FRAMEWORK = {
'PAGE_SIZE': 10,
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination'
}
除了上面配置的PageNumberPagination
分页器之外,DRF还提供了LimitOffsetPagination
和CursorPagination
分页器,值得一提的是CursorPagination
,它可以避免使用页码分页时暴露网站的数据体量,有兴趣的读者可以自行了解。如果不希望使用配置文件中默认的分页设定,可以在视图类中添加一个pagination_class
属性来重新指定分页器,通常可以将该属性指定为自定义的分页器,如下所示。
from rest_framework.pagination import PageNumberPagination
class CustomizedPagination(PageNumberPagination):
# 默认页面大小
page_size = 5
# 页面大小对应的查询参数
page_size_query_param = 'size'
# 页面大小的最大值
max_page_size = 50
class SubjectView(ListAPIView):
# 指定如何获取数据
queryset = Subject.objects.all()
# 指定如何序列化数据
serializer_class = SubjectSerializer
# 指定如何分页
pagination_class = CustomizedPagination
如果不希望数据分页,可以将pagination_class
属性设置为None
来取消默认的分页器。
数据筛选
如果希望使用CBV定制获取老师信息的数据接口,也可以通过继承ListAPIView
来实现。但是因为要通过指定的学科来获取对应的老师信息,因此需要对老师数据进行筛选而不是直接获取所有老师的数据。如果想从请求中获取学科编号并通过学科编号对老师进行筛选,可以通过重写get_queryset
方法来做到,代码如下所示。
class TeacherView(ListAPIView):
serializer_class = TeacherSerializer
def get_queryset(self):
queryset = Teacher.objects.defer('subject')
try:
sno = self.request.GET.get('sno', '')
queryset = queryset.filter(subject__no=sno)
return queryset
except ValueError:
raise Http404('No teachers found.')
除了上述方式之外,还可以使用三方库django-filter
来配合DRF实现对数据的筛选,使用django-filter
后,可以通过为视图类配置filter-backends
属性并指定使用DjangoFilterBackend
来支持数据筛选。在完成上述配置后,可以使用filter_fields
属性或filterset_class
属性来指定如何筛选数据,有兴趣的读者可以自行研究。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论