GenericAPIView, 视图工具类, 工具视图类, 视图集

目录

GenericAPIView类---泛型工具视图类

  • GenericAPIView类继承了APIView类
  • APIView类: 1. 通过重写as_view方法禁用了csrf校验, 2. 通过重写dispatch方法, 二次封装request, 进行drf三大认证, 以及二次封装response
  • GenericAPIView类定义了类属性: queryset, serializer_class, lookup_field, lookup_url_kwarg
  • GenericAPIView类定义了类方法: get_queryset, get_object, get_serializer, get_serializer_class
'''
# ...\Lib\site-packages\rest_framework\generics.py
class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None
    
    # 通过lookup_field对应的字段以及lookup_url_kwarg对应的字段值过滤出单个数据对象
    lookup_field = 'pk'  
    lookup_url_kwarg = None
    ...
    def get_queryset(self):
        ...
        queryset = self.queryset
        ...
        return queryset
        
     def get_object(self):
        queryset = self.filter_queryset(self.get_queryset())
        
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
        ...
        filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
        obj = get_object_or_404(queryset, **filter_kwargs)
        ...
        return obj
        
    def get_serializer(self, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)
        
    def get_serializer_class(self):
        ...
        return self.serializer_class
        

# ...\d_proj\api\urls.py
...
urlpatterns = [
    url(r'^v2/cars/$', views.CarGenericAPIView.as_view()),
    url(r'^v2/cars/(?P<xxx>\w+)/$', views.CarGenericAPIView.as_view()),
]
        
        
# ...\d_proj\api\views.py
...
class CarGenericAPIView(generics.GenericAPIView):
	print(type(models.Car.objects))  # <class 'django.db.models.manager.Manager'>
    print(type(models.Car.objects.all()))  # <class 'django.db.models.query.QuerySet'>
    print(type(models.Car.objects.filter()))  # <class 'django.db.models.query.QuerySet'>
    
    queryset = models.Car.objects.filter(is_delete=False).all()  
    serializer_class = serializers.CarModelSerializer
    lookup_url_kwarg = 'xxx'
    lookup_field = 'name'

    # # 群查
    # def get(self, request, *args, **kwargs):
    #     car_queryset = self.get_queryset()
    #     car_ser = self.get_serializer(instance=car_queryset, many=True)
    #     return Response(data={
    #         'code': 0,
    #         'res': car_ser.data,
    #     }, status=200)
	
    # 单查
    def get(self, request, *args, **kwargs):
        car_obj = self.get_object()
        car_ser = self.get_serializer(instance=car_obj, many=False)
        return Response(data={
            'code': 0,
            'res': car_ser.data,
        }, status=200)
'''

视图工具类

'''
# ...\Lib\site-packages\rest_framework\mixins.py
...
class CreateModelMixin:  # 单增
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        ...
        return Response(serializer.data, ...)

    def perform_create(self, serializer):
        serializer.save()
    ...


class ListModelMixin:  # 群查
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        ...
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)


class RetrieveModelMixin:  # 单查
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class UpdateModelMixin:  # 单改
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)
        ...
        return Response(serializer.data)

    def perform_update(self, serializer):
        serializer.save()

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)


class DestroyModelMixin:  # 单删
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()
'''

工具视图类

'''
# ...\Lib\site-packages\rest_framework\generics.py
from rest_framework import mixins
...


class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)
        
        
...
class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
                            mixins.UpdateModelMixin,
                            GenericAPIView):
    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)

'''

视图集

ViewSetMixin类---视图集工具类

  • ViewSetMixin类不继承任何类

  • 定义了as_view方法和view函数, 可以通过给该方法传入字典形式的参数, 实现自定义请求方式与请求处理函数的映射关系

GenericViewSet(ViewSetMixin, generics.GenericAPIView)---泛型视图集: 处理与数据库资源密切相关的请求

ViewSet(ViewSetMixin, views.APIView): 处理与数据库资源不是密切相关的请求, 例如: 登录, 短信验证码

'''
# ...\Lib\site-packages\rest_framework\viewsets.py
...
class ViewSetMixin:
    @classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        ...
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.action_map = actions

            for method, action in actions.items():
                handler = getattr(self, action)
                setattr(self, method, handler)
            ...
            return self.dispatch(request, *args, **kwargs)
        ...
        view.cls = cls
        view.initkwargs = initkwargs
        view.actions = actions
        return csrf_exempt(view)
    ...


class ViewSet(ViewSetMixin, views.APIView):
    pass


class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    pass


class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    pass


class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    pass
'''

实际开发中使用视图集时需要优化的点

  1. 重写destroy方法, 使删除操作变成将is_delete字段值修改为True
  2. 重写create方法完成单增群增, 使单增群增共用一个接口
  3. 添加群该所有字段接口, 群改部分字段接口, 群删接口
'''
# ...\d_proj\api\views.py
class CarModelViewSet(ModelViewSet):
    queryset = models.Car.objects.filter(is_delete=False).all()
    serializer_class = serializers.CarModelSerializer
    
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.is_delete = True
        instance.save()
        return Response(data={'code': 0, 'res': '删除成功'}, status=200)
	
    def create(self, request, *args, **kwargs):
        if isinstance(request.data, list):
            car_ser = self.serializer_class(data=request.data, many=True)
            car_ser.is_valid(raise_exception=True)
            instance = car_ser.save()
            re_car_ser = self.serializer_class(instance=instance, many=True)
            return Response(data={'code': 0, 'res': re_car_ser.data})
        return super().create(request, *args, **kwargs)
        
    def multiple_update(self, request, *args, **kwargs):
        return Response(data={'code': 0, 'res': '群改所有字段'}, status=200)

    def multiple_partial_update(self, request, *args, **kwargs):
        return Response(data={'code': 0, 'res': '群改部分字段'}, status=200)

    def multiple_destroy(self, request, *args, **kwargs):
        return Response(data={'code': 0, 'res': '群删'}, status=200)	

# ...\d_proj\api\urls.py
...
urlpatterns = [
    url(r'^v7/cars/$', views.CarModelViewSet.as_view({
        'get': 'list',
        'post': 'create',
        'put': 'multiple_update',
        'patch': 'multiple_partial_update',
        'delete': 'multiple_destroy',
    })),
    url(r'^v7/cars/(?P<pk>\d+)/$', views.CarModelViewSet.as_view({
        'get': 'retrieve',
        'put': 'update',
        'patch': 'partial_update',
        'delete': 'destroy',
    })),
]
'''

SimpleRouter简化...\d_proj\api\urls.py中的代码

'''
# ...\d_proj\api\urls.py
...
from .my_routers import MySimpleRouter

urlpatterns = [
    ...,
]
router = MySimpleRouter()
router.register('v7/cars', views.CarModelViewSet, basename='car')
urlpatterns.extend(router.urls)


# ...\d_proj\api\my_routers.py
from rest_framework.routers import SimpleRouter
from rest_framework.routers import Route


class MySimpleRouter(SimpleRouter):
    routes = [
        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'}
        ),
        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'}
        ),
    ]
    

# ...\Lib\site-packages\rest_framework\routers.py
class SimpleRouter(BaseRouter):

    routes = [
        # List route.
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',
            detail=False,
            ...
        ),
        # 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,
            ...
        ),
        ...,
    ]
    
    ...
    def get_default_basename(self, viewset):
        queryset = getattr(viewset, 'queryset', None)
        ...
        return queryset.model._meta.object_name.lower()
'''
上一篇:Django Restframework -序列化组件


下一篇:day 10