在完成序列化器serializers的配置过后,我们可以进一步使用DjangoRest framework提供的强大视图类API简化视图的开发。
Request和Response
(一)Request
首先需要清楚的一点是,当视图函数继承与DRF的View时,传入视图内的request对象就不再是Django默认的HttpRequest对象了,而变成了DRF扩展的Request类对象,该对象提供了更友好的数据接收方式:
1. request.data
request.data
返回解析之后的请求体数据,无需再使用data = json.loads(request.body.decode())
的方法来获取post及put等方法传输的数据。
- 包含了解析之后的文件和非文件数据
- 包含了对POST、PUT、PATCH请求方式解析后的数据
- 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据
2. request.query_params
使用request.query_params
获取前端请求中传递的关键字参数,与Django中的request.GET相同,但DRF的方法命名能更准确的指明我们在做什么。
(二) Response
与Django自带的HttpResponse对象不同,DRF还提供了一个更为便捷的响应类
Response:rest_framework.response.Response
。
使用该类构件响应对象时,不必再像之前那样需先将数据进行转换。
data数据不要是render处理之后的数据,只需传递python的内建类型数据即可,REST framework会使用renderer渲染器处理data。
- 响应方式
Response(data, status=None, template_name=None, headers=None, content_type=None)
- 参数说明
参数 | 说明 |
---|---|
data | 传递的序列化处理后的数据 |
status | 状态码,默认为200 |
template_name | 模板名称,使用HTMLRenderer 时需指明 |
headers | 用于存放响应头信息的字典 |
content_type | 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。 |
- 关于状态码
DRF提供了状态码常量,导入rest_framework.status
后使用,使用内置状态码更加规范。
DRF提供的视图View类
使用DRF提供的视图类时,我们不再继承django自带的django.views.View
类,而是继承来自DRF的VIEW
一. APIView
APIView是REST framework提供的所有视图的基类,继承自Django的View父类:rest_framework.views.APIView
。
- APIView与View的不同之处在于:
- 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
- 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
- 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
- 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
- 继承APIView的视图类代码示例
from . models import BookInfo
from .serializers import BookModelSerializer # 导入序列化器
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class BooksAPIView(APIView):
# 获取所有书
def get(self,request):
books = BookInfo.objects.all()
serializer = BookModelSerializer(books, many=True)
print(serializer.data)
return Response(serializer.data)
# 新增一本书
def post(self, request):
data_dict = request.data
serializer = BookModelSerializer(data=data_dict)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
二、GenericAPIView
此类扩展了REST框架的APIView类:rest_framework.generics.GenericAPIView
。
增加了对于列表视图和详情视图可能用到的通用支持方法,通常使用时,可搭配一个或多个Mixin扩展类。
基本设置
使用继承于GenericAPIView的视图类时,需要先定义基本类属性:
(1)queryset
:列表视图的查询集
(2)serializer_class
:视图使用的序列化器
以上两个为必须设置的属性
(3)lookup_field
:用于执行单个模型实例的对象查找的模型字段,不设置时默认为pk
字段
(4)lookup_url_kwarg
:查询单一数据时URL中的参数关键字名称,默认与look_field相同
(5)pagination_class
:分页控制类
(6)filter_backends
:用于过滤查询集的过滤器后端类列表基本方法
(1)get_queryset(self)
: 返回视图使用的查询集
(2)get_serializer_class(self)
: 返回序列化器类
(3)get_object(self)
: 返回lookup_field
设置指定的模型类数据对象。
3.继承GenericAPIView视图类的代码示例
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
class BooksAPIView(GenericAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 获取所有
def get(self,request):
books = self.get_queryset()
serializer = self.get_serializer(books, many=True)
return Response(serializer.data)
# 新增一本书
def post(self, request):
data_dict = request.data
serializer = self.get_serializer(data_dict)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
看起来代码量并没有减少,只是将序列化器的初始化、数据集的查询提取了出来。
但GenericAPIView类主要是联合它的Mixin类一起使用的。
三、Mixin扩展类
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin
DRF总共提供了5个Mixin扩展类,他们只提供操作的方法,而需要同时继承GenericAPIView类,并继承对用功能的Mixin类:
Minx类 | 作用 | 调用方式 |
---|---|---|
ListModelMixin | 实现查询集功能(get) | list |
CreateModelMixin | 实现创建和保存功能(post) | create |
RetrieveModelMixin | 实现查询指定单一数据功能(get) | retrieve |
UpdateModelMixin | 实现更新功能(put) | update |
DestroyModelMixin | 实现删除功能(delete) | destroy |
- 使用代码示例
该视图类需要实现查询所有书功能、创建一本新书的功能,因此除继承GenericAPIView外, 还需继承ListModelMixin, CreateModelMixin类。
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin,ListModelMixin
class BooksAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 获取所有
def get(self,request):
return self.list(request)
# 新增一本书
def post(self, request):
return self.create(request)
class BookAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
# 获取指定id书
def get(self,request, pk):
return self.retrieve(request, pk)
# 修改指定书信息
def put(self, request, pk):
return self.update(request, pk)
# 删除指定书
def delete(self,request, pk):
return self.delete(request,pk)
可以看到,使用Mixin扩展类后,代码量大大缩减,连逻辑代码都被封装起来了。
- mixin源码示例
mixin类在内部定义了方法将:数据集的查询及获取、页码操作、序列化器的调用、Response响应 都封装在了一起,我们需要做的就只是继承然后调用该内部方法即可ListModelMixin源码示例:
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
其内部相当于将我们写的逻辑代码部分都封装起来了,因为其逻辑流程都是相同的。mixin类提供.list()和.create()等操作,然后我们将这些get和post方法明确地绑定到适当的操作上。使这种类型的代码极大减少。
四、基于GenericAPIView和Mixin扩展类的子类
到目前为止,使用Mixin的扩展类已经让我们的代码量足够简洁了,但Rest framework还进行了进一步的封装,在符合条件的情况下可以连定义get、post等方法及return的语句也不用再我们自己写。
- 可用子类试图介绍
一共内置了9个可用子类试图
子类视图类 | 作用 | 对应方法 |
---|---|---|
CreateAPIView | 新建 | post |
ListAPIView | 查询所有 | get |
RetireveAPIView | 查询指定 | get |
DestoryAPIView | 删除指定 | delete |
UpdateAPIView | 更新指定 | put |
ListCreateAPIView | 查询所有及创建 | post、get |
RetrieveUpdateAPIView | 查询指定及更新 | get、put |
RetrieveDestoryAPIView | 查询指定及删除 | get、delete |
RetrieveUpdateDestoryAPIView | 查询指定、更新、删除 | get、put、delete |
- 使用代码示例
只需要不过10行代码,就可以实现最初基于Django的View类时需要写的100多行代码效果。
需要我们自己实现的只有数据集的定义及序列化器的定义,其余都基于序列化器进行了封装完成。
from . models import BookInfo
from .serializers import BookModelSerializer
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
class BooksAPIView(ListCreateAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
class BookAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = BookModelSerializer
queryset = BookInfo.objects.all()
3.源码示例
其实源码内就是封装了对方法的定义及return
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for retrieving, updating or deleting a model instance.
"""
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 patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
总结
我用自己的话总结了这些不同的类到底实现了什么功能,可能有欠妥的地方,欢迎提出。
Serializer:构建序列化器,视图函数内不再需要自己构造键值对数据格式。
Response:DRF提供的Response对象返回数据时,不需要再次转换数据格式,只需将request。data传递给它即可,它能完成自动处理。
APIView:基本DRF视图类,提供了新的Request类。使用request.data可直接接收转换后的数据。
GenericAPIView:基于APIView,从视图函数中提取出了序列化器和查询集,主要用于配合Mixin类使用。
Mixin扩展类ListModelMixin等:基于object,视图类使用时需要同时继承Mixin类和Generic类。此处实现了逻辑代码封装,将数据接收、查询、验证、响应都封装在了list、create、retrive、update、destroy方法里面,只需再调用这些封装好的方法即可。
扩展类子类CreateAPIView等:将方法的定义和return返回都封装了,我们在视图类中需要做的只剩指定序列化器与查询集,其继承类将完成剩下的所有。