文章目录
一、 mixins 和 generics.GenericAPIView
示例 model
# 服务器表
class Server(models.Model):
hostname = models.CharField(verbose_name='主机名', max_length=128, unique=True)
manage_ip = models.GenericIPAddressField(verbose_name='管理 IP', null=True, blank=True)
latest_date = models.DateTimeField(verbose_name='更新时间', default=timezone.now, null=True)
create_at = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
# 硬盘表
class Disk(models.Model):
slot = models.CharField(verbose_name='插槽位', max_length=8)
model = models.CharField(verbose_name='磁盘型号', max_length=32)
capacity = models.FloatField(verbose_name='磁盘容量GB')
pd_type = models.CharField(verbose_name='接口类型', max_length=32)
server_obj = models.ForeignKey(
Server, related_name='disk',
verbose_name='所属服务器', on_delete=models.CASCADE)
编写类视图
在上一章节中,我们已经知道
ApiView
和 DRF 的Serializer
结合, 可以很好的处理图片类型的字段,以及可以很好的处理外键字段。
其实,ApiView
是后面我们所要介绍的所有 DRF View 的基类。
generics.GenericAPIView 提供了更多的属性,从而让开发人员写更少的代码,实现更多的功能。这些属性包括但不限于:
queryset = None
serializer_class = None
注意: 这里使用的序列化类还是之前定义的基于 Model 的 Serializer
from rest_framework.response import Response
from rest_framework import mixins
from rest_framework import generics
from .serializers import ServerSerializer, DiskSerializer
from cmdb.models import Server, Disk
class ServerListView(mixins.ListModelMixin,
generics.GenericAPIView):
"""服务器列表页"""
queryset = Server.objects.all()
serializer_class = ServerSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
mixins.ListModelMixin
提供.list()
方法,用于提供一组数据。
generics.GenericAPIView
提供分页功能,和
配置 URL
重启 Django 测试
查看页面格式的 API
查看 JSON 格式的 API
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J9lDdnHj-1624288957713)(evernotecid://BBD579E0-7127-4377-8E81-47BEA574FA91/appyinxiangcom/25594833/ENResource/p535)]
JSON 数据如下
关于 mixin 和基础核心类
基类提供核心功能,就是处理请求和响应,有 as_view
方法。
mixin
类提供 .list()
操作, 就是处理数据,提供分页,序列化数据等功能。
然后我们使用自定义的类继承这些类,将这些和 get
方法明确地绑定到适当的操作上。
其他 mixin 的操作类
官方示例和好的诠释了这些操作
class SnippetDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
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)
Mixins 总结表
mixin | mixin 实现的操作方法 | 对应HTTP请求的方法 | 需要配合实现通用视图中的方法 |
---|---|---|---|
mixins.ListModelMixin | .list() 返回一个queryset的列表 | GET | .get() |
mixins.RetrieveModelMixin | .retrieve() 返回一个具体实例 | GET | .get() |
mixins.CreateModelMixin | .create() 创建一个实例 | POST | .post() |
mixins.UpdateModelMixin | .update() 对某个实例进行更新 | PUT/PATCH | .put() |
mixins.DestroyModelMixin | .destroy() 删除某个实例 | DELETE | .delete |
PUT/PATCH
的区别
patch方法用来更新局部资源,这句话我们该如何理解?
假设我们有一个UserInfo,里面有userId, userName, userGender等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName,这时候的更新怎么做?
人们通常(为徒省事)把一个包含了修改后userName的完整userInfo对象传给后端,做完整更新。但仔细想想,这种做法感觉有点二,而且真心浪费带宽(纯技术上讲,你不关心带宽那是你土豪)。
于是patch诞生,只传一个userName到指定资源去,表示该请求是一个局部更新,后端仅更新接收到的字段。
而put虽然也是更新资源,但要求前端提供的一定是一个完整的资源对象,理论上说,如果你用了put,但却没有提供完整的UserInfo,那么缺了的那些字段应该被清空
补充:
最后再补充一句,restful只是标准,标准的意思是如果在大家都依此行事的话,沟通成本会很低,开发效率就高。但并非强制(也没人强制得了),所以你说在你的程序里把方法名从put改成patch没有任何影响,那是自然,因为你的后端程序并没有按照标准对两个方法做不同处理,她的表现自然是一样的
PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的。
幂等是一个数学和计算机学概念,在计算机范畴内表示一个操作执行任意次对系统的影响跟一次是相同。
二、 使用基于类的通用视图
使用 mixin
类,我们重写了视图,使用的代码比以前略少,但我们可以更进一步。REST 框架提供了一组已经混合好的通用视图,我们可以使用它来进一步减少我们的 views.py
模块中视图的代码。
部分通用视图源码
# generics.py 模块中
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
可以看出, 由于
generics.ListAPIView
继承了GenericAPIView
和mixins.ListModelMixin
并且(也是主要原因)自己本身实现了.get()
方法,
所以我们自己的视图继承generics.ListAPIView
后,就不用写.get()
方法了。
视图使用示例
from rest_framework import generics
from .serializers import ServerSerializer, DiskSerializer
from cmdb.models import Server, Disk
class ServerGenericView(generics.ListAPIView):
queryset = Server.objects.all()
serializer_class = ServerSerializer
class DiskGenericView(generics.ListAPIView):
queryset = Disk.objects.all()
serializer_class = DiskSerializer