DjangoRest framework-视图类API实现极简开发

在完成序列化器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。

  1. 响应方式
    Response(data, status=None, template_name=None, headers=None, content_type=None)
  2. 参数说明
参数 说明
data 传递的序列化处理后的数据
status 状态码,默认为200
template_name 模板名称,使用HTMLRenderer 时需指明
headers 用于存放响应头信息的字典
content_type 响应数据的Content-Type,通常此参数无需传递,REST framework会根据前端所需类型数据来设置该参数。
  1. 关于状态码
    DRF提供了状态码常量,导入rest_framework.status后使用,使用内置状态码更加规范。

DRF提供的视图View类

使用DRF提供的视图类时,我们不再继承django自带的django.views.View类,而是继承来自DRF的VIEW

一. APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类:rest_framework.views.APIView

  1. APIView与View的不同之处在于:
  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
  1. 继承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扩展类。

  1. 基本设置
    使用继承于GenericAPIView的视图类时,需要先定义基本类属性:
    (1) queryset :列表视图的查询集
    (2) serializer_class :视图使用的序列化器
    以上两个为必须设置的属性
    (3)lookup_field:用于执行单个模型实例的对象查找的模型字段,不设置时默认为pk字段
    (4)lookup_url_kwarg:查询单一数据时URL中的参数关键字名称,默认与look_field相同
    (5)pagination_class:分页控制类
    (6)filter_backends:用于过滤查询集的过滤器后端类列表

  2. 基本方法
    (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
  1. 使用代码示例
    该视图类需要实现查询所有书功能、创建一本新书的功能,因此除继承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扩展类后,代码量大大缩减,连逻辑代码都被封装起来了。

  1. 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的语句也不用再我们自己写。

  1. 可用子类试图介绍
    一共内置了9个可用子类试图
子类视图类 作用 对应方法
CreateAPIView 新建 post
ListAPIView 查询所有 get
RetireveAPIView 查询指定 get
DestoryAPIView 删除指定 delete
UpdateAPIView 更新指定 put
ListCreateAPIView 查询所有及创建 post、get
RetrieveUpdateAPIView 查询指定及更新 get、put
RetrieveDestoryAPIView 查询指定及删除 get、delete
RetrieveUpdateDestoryAPIView 查询指定、更新、删除 get、put、delete
  1. 使用代码示例
    只需要不过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返回都封装了,我们在视图类中需要做的只剩指定序列化器与查询集,其继承类将完成剩下的所有。

你可能感兴趣的:(DjangoRest framework-视图类API实现极简开发)