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返回都封装了,我们在视图类中需要做的只剩指定序列化器与查询集,其继承类将完成剩下的所有。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容