Django rest-framework视图家族

时间:2020-01-06 00:06:38   收藏:0   阅读:143

视图家族

from rest_framework import views,generics,mixins,viewsets

视图类 GenericAPIView

两大视图类:APIView、GenericAPIView

APIView

from rest_framework.views import APIView

GenericAPIView

from rest_framework.generics import GenericAPIView

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

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

使用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

五大工具类

六大工具方法

使用mixins的六大工具方法

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

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

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

使用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

使用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')

原文:https://www.cnblogs.com/ghylpb/p/12154244.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!