zoukankan      html  css  js  c++  java
  • DRF视图集的使用

    # 原创,转载请留言联系

    如果要把同一种http请求方法的多个接口放在同一个视图中,比如:查询多条数据和一条数据都是get请求,放在同一个视图里,应该怎么做呢???

    如果直接放在一起,会怎样呢?

    # 视图:
    class DepartmentTestView(ListAPIView, RetrieveAPIView):
        queryset = Department.objects.all()
        serializer_class = DepartmentSerializer
    
    # 路由:
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^departments$',views.DepartmentTestView.as_view()),
        url(r'^departments/(?P<pk>d+)$',views.DepartmentTestView.as_view())
    ]

    当访问/departments时,匹配对路由,然后到达视图,找get请求的视图,先找到了ListAPIView,执行,正确的返回了数据。

    当访问/departments/1时,匹配对路由,然后到达视图,找get请求的视图,先找到ListAPIView,执行,返回了查找全部数据的结果。不是我们想要的结果。

    解决办法:使用视图集

    1.ViewSet

    • 继承自APIView与ViewSetMixin
    • 继承ViewSetMixin的作用是实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。
    • 在ViewSet中,没有提供任何 action方法,需要我们自己实现 action方法(和继承APIView一样,要自己创建序列化器对象,自己校验数据,自己存数据库,自己序列化等...)

     示例:

    首先是视图的代码:

    class DepartmentViewSet(ViewSet):
        def list(self,request):
            """查询全部部门"""
            dep = Department.objects.all()
            serializer = DepartmentSerializer(instance=dep,many=True)
            return Response(data=serializer.data)
    
        def create(self,request):
            """新增一个部门"""
            data_dict = request.data
            serializer = DepartmentSerializer(instance=None,data=data_dict)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
    
        def retrieve(self,request,pk):
            """查询一个部门"""
            try:
                dep = Department.objects.get(id=pk)
            except Department.DoesNotExist:
                return Response(status=status.HTTP_404_NOT_FOUND)
            serializer = DepartmentSerializer(instance=dep)
            return Response(serializer.data)
    
        def update(self,request,pk):
            """修改一个部门"""
            try:
                dep = Department.objects.get(id=pk)
            except Department.DoesNotExist:
                return Response(status=status.HTTP_404_NOT_FOUND)
            data_dict = request.data
            serializer = DepartmentSerializer(instance=dep,data=data_dict)
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(serializer.data)
    
        def delete(self,request,pk):
            """删除一个部门"""
            try:
                dep = Department.objects.get(id=pk)
            except Department.DoesNotExist:
                return Response(status=status.HTTP_404_NOT_FOUND)
            dep.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)

    然后是路由的配置:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^departments$',views.DepartmentViewSet.as_view({'get':'list','post':'create'})),
        url(r'^departments/(?P<pk>d+)$',views.DepartmentViewSet.as_view({'get':'retrieve','post':'update','delete':'delete'}))
    ]

    注意:

    函数名(list、create、retrieve、update、delete)可以自定义的,也可以根据实际情况定义函数。

    2.GenericViewSet

    • 使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写
    • 因为这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法,而Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView
    • GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIView与ViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

    示例:

    首先是视图的代码:

    class DepartmentViewSet(ListModelMixin,CreateModelMixin,RetrieveModelMixin,
                            UpdateModelMixin,DestroyModelMixin,GenericViewSet):
    
        queryset = Department.objects.all()
        serializer_class = DepartmentSerializer

    然后是路由的配置:

    urlpatterns = [
        url(r'^departments$',views.DepartmentViewSet.as_view({'get':'list','post':'create'})),
        url(r'^departments/(?P<pk>d+)$',views.DepartmentViewSet.as_view({
            'get':'retrieve','put':'update','delete':'destroy'
        }))
    ]

    注意:

    路由配置中,例如'get':'list',对应的是请求方法,ListModelMixin里面的方法。特别是‘list’,一定要点进类里面,看下方法名是什么,再写在路由里面,不然无法调用类里面的方法,也就返回不了响应对象。

    拓展:

    如果这几个类满足不了需求,可以仿照ViewSet的方法自定义方法。如果自定义的方法要用到不同的序列话器,可以这样做:

    def get_serializer_class(self):
              """修改部门名称的接口,使用不同的序列化器"""
              if self.action == '[方法名]':
                  return [自定义的序列器]
              else:
                  return DepartmentSerializer

    3.ModelViewSet

    • 继承自GenericViewSet
    • 包括了 ListModelMixinRetrieveModelMixinCreateModelMixinUpdateModelMixinDestroyModelMixin
    • 和第2点的用法一样

    4.ReadOnlyModelViewSet

    • 继承自 GenericViewSet
    • 包括了 ListModelMixinRetrieveModelMixin
    • 和第2点的用法一样
  • 相关阅读:
    EF 关系规则(一对一、一对多、多对多...)
    EF框架中加子类后出现列名 'Discriminator' 无效问题
    .net下Ueditor配置(主要讲解上传功能配置)
    同构数查找程序的优化过程 Anthony
    Effective STL 条款17 Anthony
    C 语言中的数组类型和数组指针类型. Anthony
    Effective STL 条款18 Anthony
    RDLC之自定義數據集二
    给Calendar添加标签
    Profile学习
  • 原文地址:https://www.cnblogs.com/chichung/p/9941953.html
Copyright © 2011-2022 走看看