Django rest-framework类视图大全

2023-05-16

视图分类

  • 视图类 GenericAPIView:包含两大视图类(APIView、GenericAPIView)
  • 视图工具类 mixins:包含五大工具类,六大工具方法
  • 工具视图类 generics:包含九大工具视图类,一堆mixins工具类与GenericAPIView视图基类组合
  • 视图集 viewsets:可自定义映射关系
from rest_framework import views,generics,mixins,viewsets

视图类 GenericAPIView

两大视图类:APIView、GenericAPIView

APIView

from rest_framework.views import APIView
  • 继承基本View,拥有View所有的功能
  • 重写了as_view()方法,禁用了csrf认证
  • 重写dispatch,封装请求、响应、渲染、异常、解析、三大认证模块
  • 封装一堆属性,可完成视图类的局部配置

GenericAPIView

from rest_framework.generics import GenericAPIView
  • 继承APIView,拥有APIView所有的功能
  • 提供get_queryset方法:配置queryset类属性,群查获取QuerySet对象
  • 提供get_object方法:配置lookup_url_kwarg类属性,单查获取单个对象
  • 提供get_serializer方法:配置serializer_class类属性,提供序列化类并使用自定义的序列化类序列化

总结:GenericAPIView就是在APIView基础上额外提供了三个方法和三个类属性,如果不配合视图工具类,则体现不出来优势所在

使用它的好处:视图中的增删改查逻辑其实大差不差,但操作的资源不一致(操作的资源指的是models模型类和序列化类),将资源形成配置,操作逻辑一致,就可以完成封装

使用GenericAPIView类

  • 继承GenericAPIView类
  • 配置对哪个表进行操作
  • 配置使用哪个序列化类

群查

from rest_framework.generics import GenericAPIView

class ViewGenericAPIView(GenericAPIView):
    # 配置关联表的属性
    # 如果只写models.Car.objects的话那就是manager对象,不是QuerySet对象
    queryset = models.Car.objects.filter(is_delete=False).all()
    # 配置使用的序列化类
    serializer_class = serializer.CarModelSerializer

    # 群查
    def get(self,request,*args,**kwargs):
        # 帮我们去表里面拿数据
        car_query = self.get_queryset()
        # 帮我们去序列化
        car_ser = self.get_serializer(car_query,many=True)
        return APIResponse(results=car_ser.data)

单查

from rest_framework.generics import GenericAPIView

class ViewGenericAPIView(GenericAPIView):
    # 配置关联表的属性
    # 如果只写models.Car.objects的话那就是manager对象,不是QuerySet对象
    queryset = models.Car.objects.filter(is_delete=False).all()
    # 配置使用的序列化类
    serializer_class = serializer.CarModelSerializer
    # 配置查询的条件为pk,单查走pk过滤的条件
    lookup_url_kwarg = 'pk'

    # 单查
    def get(self,request,*args,**kwargs):
        car_obj = self.get_object()
        car_ser = self.get_serializer(car_obj)
        return APIResponse(results=car_ser.data)

视图工具类 mixins

  • 在GenericAPIView的基础上提供了五个类,六个方法六大接口(单查、群查、单增、单整体改、单局部改、单删)
  • 使用的时候需要配合继承GenericAPIView类

五大工具类

  • RetrieveModelMixin:单查类
  • ListModelMixin:群查类
  • CreateModelMixin:单增类
  • UpdateModelMixin:单整体和单局部改类
  • DestroyModelMixin:单删类

六大工具方法

  • retrieve:单查方法
  • list:群查方法
  • create:单增方法
  • update:单整体改方法
  • partial_update:单局部改方法
  • destroy:单删方法

使用mixins的六大工具方法

  • 继承GenericAPIView类
  • 配置对哪个表进行操作
  • 配置使用哪个序列化类
from rest_framework import mixins

class ViewMixinsAPIView(mixins.RetrieveModelMixin,
                        mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        GenericAPIView):
    queryset = models.Car.objects.filter(is_delete=False).all()
    serializer_class = serializer.CarModelSerializer
    lookup_url_kwarg = 'pk'

    # 单查群查
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            return self.retrieve(request, *args, **kwargs)
        return self.list(request, *args, **kwargs)

    # 单增
    def post(self, request, *args, **kwargs):
        return self.create(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):
        # django中的删除是真正的删除
        # 删除接口一般是自己实现重写到的,因为真正的业务不需要真正的删除
        pass
        # django源代码中是真的删除
        return self.destroy(request, *args, **kwargs)

工具视图类 generics

工具类加视图类的组合,只要继承工具该类,就有响应的方法,

  • 帮我们将不同的mixins工具类与GenericAPIView视图类进行组合,我们不再需要继承GenericAPIView类
  • 不同的组合封装成一个个的类,实现对应的请求方法(get、post、put、patch、delete)

随后就是用单查就继承单查的接口,用群查就继承群查的接口即可。

使用generics的工具类实现接口

  • 配置对哪个表进行操作
  • 配置使用哪个序列化类
from rest_framework import generics

class ViewGenericsAPIView(generics.RetrieveAPIView,
                         generics.ListAPIView,
                         generics.CreateAPIView,
                         generics.UpdateAPIView,
                         generics.DestroyAPIView):
    # 单查和群查只能使用一个get,具体调用哪个要看继承的顺序
    queryset = models.Car.objects.filter(is_delete=False).all()
    serializer_class = serializer.CarModelSerializer
    lookup_url_kwarg = 'pk'

    # 有删除需求的接口继承DestroyAPIView,重写destroy完成字段的删除
    def destroy(self, request, *args, **kwargs):
        pass

视图集 viewsets

  • 重写as_view方法,增加action参数(可以完成路由层的请求方法映射关系)
  • 可以在路由层中自定义请求方法的映射关系

使用viewsets的视图集类实现接口

  • 配置对哪个表进行操作
  • 配置使用哪个序列化类

可自定义路由层中请求方法的映射关系来实现接口

路由层

url(r'^v5/cars/$', views.ViewViewsetsAPIView.as_view({
        "get":"list",
        "post":"create"
    })),
    url(r'^v5/cars/(?P<pk>\d+)/$', views.ViewViewsetsAPIView.as_view({
        "get":"retrieve",
        "put":"update",
        "patch":"partial_update",
        "delete":"destroy"
    })),

视图层

from rest_framework import viewsets
# 视图集类
class ViewViewsetsAPIView(viewsets.ModelViewSet):
    queryset = models.Car.objects.filter(is_delete=False).all()
    serializer_class = serializer.CarModelSerializer
    lookup_url_kwarg = 'pk'

 

完善viewsets的视图集类实现接口

以上的步骤我们继承视图集的ModelViewSet类实现了六大接口,但是从实际开发角度分析有很多不合理的点:

  1. 没有群增,群整体改,群局部改,群删四个接口
  2. 删除只做字段的修改
  3. 响应的结果只有数据,没有数据状态码和状态信息

所以针对以上问题,我们解决一下:

路由层配置

url(r'^v5/cars/$', views.ViewViewsetsAPIView.as_view({
        "get":"list",
        "post":"create",
        "put":"many_update",
        "patch":"many_partial_update",
        "delete":"many_destroy"
    })),
    url(r'^v5/cars/(?P<pk>\d+)/$', views.ViewViewsetsAPIView.as_view({
        "get":"retrieve",
        "put":"update",
        "patch":"partial_update",
        "delete":"destroy"
    })),

实现群增,群整体改,群局部改,群删四个接口

视图层配置

    # 群整体改
    def many_update(self,request,*args,**kwargs):
        try:
            pks = []
            for dic in request.data:
                pks.append(dic.pop('pk'))
            car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
            if len(pks) != len(car_query):
                raise Exception('pk对象不存在')
        except Exception as e:
            return Response({'detail': '%s' % e}, status=400)
        car_ser = self.get_serializer(instance=car_query,data=request.data,many=True)
        car_ser.is_valid(raise_exception=True)
        car_obj = car_ser.save()
        return APIResponse(results=self.get_serializer(car_obj,many=True).data)

    
    
    # 群局部改
    def many_partial_update(self,request,*args,**kwargs):
        try:
            pks = []
            for dic in request.data:
                pks.append(dic.pop('pk'))
            car_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
            if len(pks) != len(car_query):
                raise Exception('pk对象不存在')
        except Exception as e:
            return Response({'detail': '%s' % e}, status=400)
        car_ser = self.get_serializer(instance=car_query,data=request.data,many=True,partial=True)
        car_ser.is_valid(raise_exception=True)
        car_obj = car_ser.save()
        return APIResponse(results=self.get_serializer(car_obj,many=True).data)

    
    
    # 群删
    def many_destroy(self,request,*args,**kwargs):
        pks = request.data
        try:
            rows = models.Car.objects.filter(is_delete=False, pk__in=pks).update(is_delete=True)
        except:
            return APIResponse(1, '数据有误')
        if rows:
            return APIResponse(msg='删除成功')
        return APIResponse(1, '删除失败')

    
    
    # 群增和单增必须使用同一个接口,都要走create方法,重写create方法,使用逻辑拆分
    def create(self, request, *args, **kwargs):
        if isinstance(request.data,list):
            car_ser = self.get_serializer(data=request.data,many=True)
            car_ser.is_valid(raise_exception=True)
            car_obj = car_ser.save()
            return APIResponse(msg="群增成功",results=self.get_serializer(car_obj,many=True).data)
        return super().create(request, *args, **kwargs)

实现删除只做字段的修改

    # 解决2 destroy方法完成对字段的修改
    def destroy(self, request, *args, **kwargs):
        car_obj = self.get_object()
        if not car_obj:
            return APIResponse(1,msg="删除失败")
        car_obj.is_delete = True
        car_obj.save()
        return APIResponse(msg="删除成功")

实现返回信息包含数据状态码和状态信息

    # 解决3 群查有状态码和状态信息,重写list方法
    def list(self, request, *args, **kwargs):
        response = super().list(request, *args, **kwargs)
        return APIResponse(results=response.data)

    # 重写retrieve方法,单查有状态码和状态信息
    def retrieve(self, request, *args, **kwargs):
        response = super().retrieve(request, *args, **kwargs)
        return APIResponse(results=response.data)

路由组件(了解)

使用SimpleRouter结合视图组件进行路由配置

from django.conf.urls import url,include
from rest_framework.routers import SimpleRouter
router = SimpleRouter()

# 将所有路由与ViewSet视图类的都可以注册,会产生'^v5/cars/$' 和 '^v5/cars/(?P<pk>[^/.]+)/$'的url
router.register('v5/cars',views.ViewViewsetsAPIView,basename='car')

urlpatterns = [
    # 第一种添加子列表方式
    url(r'^', include(router.urls)),
]
# 第二种添加子列表方式
# urlpatterns.extend(router.urls)

路由组件源码部分

如果想实现其他映射关系的话,修改源码就行了

routes = [
        # List route.
        # 群增,如果想要在url中奖请求方式映射关系改变的话,可以重写这个
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
    ]

或者自定义路由对象

from rest_framework.routers import Route, DynamicRoute, SimpleRouter as DRFSimpleRouter

class SimpleRouter(DRFSimpleRouter):
    routes = [
        # List route.  /资源s/
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',  # 群查
                'post': 'create',  # 单增、群增
                'put': 'many_update',  # 群整改
                'patch': 'many_partial_update',  # 群局改
                'delete': 'many_destroy',  # 群删
            },
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.  /资源s/(pk)/
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',  # 单查
                'put': 'update',  # 单整改
                'patch': 'partial_update',  # 单局改
                'delete': 'destroy'  # 单删
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
    ]

# 对外提供router对象
router = SimpleRouter()
# eg: router.register('users', UserModelViewSet, basename='user')
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django rest-framework类视图大全 的相关文章

  • 1、FreeRTOS使用,Main函数中需要做的事情

    1 硬件初始化 xff08 也可以放在SystemInit中 xff09 时钟初始化 中断优先级分组 中断优先级分配 xff08 设置 xff09 外设初始化 xff08 时钟 xff0c GPIO xff0c 配置参数 xff0c 是否使
  • ubuntu22.04系统配置(一)(后续有kali的配置)

    ubuntu22 04系统配置深度学习 xff08 一 xff09 xff08 后续有kali的配置 xff09 摘要系统下载以及U盘拷贝系统的基本配置nvidia smi 摘要 配置这个东西真的踩了好多坑 xff0c 之前一直用的Wind
  • GINet:Graph Interaction Network for Scene Parsing(ECCV 2020)详解

    论文地址 xff1a https arxiv org pdf 2009 06160 pdf 一 背景 Scene Parsing 任务属于语义分割的一个分支 xff0c 也是把每个像素点分成一个具体的语义类别 xff0c 它和常见的语义分割
  • C++ string切割,分解字符串,C 库函数 - strtok()

    声明 下面是 strtok 函数的声明 char strtok char str const char delim 参数 str 要被分解成一组小字符串的字符串 delim 包含分隔符的 C 字符串 返回值 该函数返回被分解的第一个子字符串
  • BGP详解

    BGP协议详解 BGP是一种边界网关协议 但是也属于动态路由协议 一 BGP的特征 xff08 一种外部路由协议 xff0c 用来在AS之间传递路由信息 xff0c 是一种增强版的距离矢量协议 xff09 1 可靠的路由更新机制 传输协议
  • el-input-number 如何实现默认不填充0

    只需要把数据设置未 undefined 的就可以了 lt el input number v model 61 num 64 change 61 handleChange min 61 1 max 61 10 label 61 描述文字 g
  • vue项目 el-input输入框字符限制,只显示英文及数字

    element的el input没有限制输入的内容 xff0c 想要限制输入内容就需要自己来开发 xff0c 我使用的方式是正则来判断进行再次赋值实现的 xff0c 不废话上代码 xff1b lt el input v model 61 3
  • cdn方式使用vue和element-ui进行前端开发

    安装 按照vue和element ui的官网开发指南中提供的cdn安装方式 xff0c 直接以script方式引入 要注意引入顺序 span class token comment lt 引入样式 gt span span class to
  • vue el-table 如何实现表格根据分页索引自增长

    在el table 里设置type 61 index xff0c 可以实现表格的索引自增长 xff0c 但是如果我们给表格增加了分页 xff0c 切换页面索引任然是从1 20 xff08 20是自己分页的数量 xff09 xff0c 那么想
  • Vue的计算属性和监听属性

    1 计算属性 computed 当依赖数据发生变化时 xff0c 计算属性会被重新计算 有且只有在依赖数据发生变化时它才会重新计算 xff0c 其他的数据变化对计算属性 应用场景 xff1a 数据的计算显示 v for用v if的计算 sp
  • Element UI el-form-item 遍历表单校验规则

    一 遍历表单校验规则实现案例 prop内容为 遍历数据 43 index 43 校验数据 span class token operator lt span div span class token keyword class span s
  • uni-app引入uView2.0的步骤

    引入uVIew组件可以使用uni app市场插件安装插件即可 xff0c 也可以使用npm下载安装 xff0c 不过使用npm需要在pages json使用easycom属性引用需要的组件类 在uni app插件市场右上角选择使用HBuil
  • Vue-cli创建项目步骤

    一 使用 vue cli 搭建项目 下面整个过程是基于已经安装node js和cnpm的基础上 xff0c node js如何安装就不在这里详说了 xff08 1 xff09 全局安装 vue cli xff0c 在命令提示窗口执行 xff
  • keil5建立工程

    1 xff0c 确认工程代码 主要包括代码的目录或者代码的svn路径 xff0c 其次再来确认代码的编译方法 xff0c 确认该代码是需要keil5编译还是linux gcc 43 makefile 编译 2 xff0c 确认编译手段 确认
  • win10下 frpc的开机自启动

    frp可以用来进行内网穿透 xff0c 其具体实现原理可以参考网上其他教程 xff0c 本文主要描述用户端程序frpc exe在win10下的一种开机自启动方法 本地组策略 在完成配置最后 xff0c 需要进行自启动配置 xff0c 一般的
  • qt 设置背景图片、背景色步骤

    拖一个label 控件 label 上右键选择改变样式表 xff0c 添加资源选择图片 一 设置背景图 background image xff1a 二 铺满整个label border image xff1a 三 添加图片 xff0c i
  • QT 设置按钮QPushButton 圆角、渐变色背景、背景图片、鼠标放上去、鼠标按下效果、透明背景

    设置按钮圆角 渐变色背景 背景图片 鼠标放上去 鼠标按下效果 透明背景 效果 xff1a 一 设置四角圆角 xff1a 二 设置下 左圆角 按钮鼠标放上去改变背景色 三 设置上 右圆角 四 按钮设置背景图片 xff0c 鼠标放上去 按下 更
  • processlist中状态详解

    在processlist中 xff0c 看到哪些运行状态时要引起关注 xff0c 主要有下面几个 xff1a 状态建议copy to tmp table执行ALTER TABLE修改表结构时建议 xff1a 放在凌晨执行或者采用类似pt o
  • 在oVirt上安装Win11虚拟机

    在oVirt上安装Win11虚拟机
  • 【Debugging】树莓派 SSH连接失败解决

    问题描述 在使用SSH连接时出现如下错误 xff1a Remote side unexpectedly closed network connection 解决方案 修改ssh的配置文件 etc ssh sshd config xff0c

随机推荐