• day 77


    视图家族

    views视图类

    • APIView
    Copy"""
    1.继承View类
    2.重写了as_view方法: 局部禁用csrf
    3.重写了dispatch方法: 请求, 响应, 解析, 渲染, 异常, 三大认证
    4.一系列类属性: 局部和全局配置
    作用: drf最底层视图, 所有视图直接或者间接继承了APIView, 理论上可以完成所有接口需求
    """
    
    • GenericAPIView
    Copy"""
    1.继承了APiView
    2.get_queryset方法, 需要在视图类中配置queryset类属性
    3.get_object方法,  可以在视图类中配置lookup_url_kwarg和lookup_field类属性, 默认是按pk
    4.get_serializer方法, 需要在视图类中配置serializer_class类属性
    
    总结:GenericAPIView就是在APIView基础上额外提供了三个方法,三个类属性,如果不配合视图工具类,体现不出优势
    目的:视图中的增删改查逻辑相似,但操作的资源不一致,操作资源就是操作 资源对象们(queryset)、资源对象(object)以及资源相关的序列化类(serializer),将这三者形成配置,那操作逻辑就一致,就可以进行封装
    """
    
    class GenericAPIView(views.APIView):
        # 需要自己配置的几个属性
        queryset = None
        serializer_class = None
        lookup_field = 'pk'
        lookup_url_kwarg = None
    
        def get_queryset(self):
            # queryset为None就抛异常, 因此我们要在视图类中自定义queryset属性
            assert self.queryset is not None, (
                "'%s' should either include a `queryset` attribute, "
                "or override the `get_queryset()` method."
                % self.__class__.__name__
            )
            
            ...
            
            return queryset
    
        def get_object(self):
            queryset = self.filter_queryset(self.get_queryset())
    
            # 如果设置了就按lookup_url_kwarg, 没有设置就按lookup_field, 也就是"pk" 
            lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
            assert lookup_url_kwarg in self.kwargs, (
                'Expected view %s to be called with a URL keyword argument '
                'named "%s". Fix your URL conf, or set the `.lookup_field` '
                'attribute on the view correctly.' %
                (self.__class__.__name__, lookup_url_kwarg)
            )
    
            ...
    
            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):
            # serializer_class为None就抛异常, 因此我们要在视图类中自定义serializer_class属性
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer_class()` method."
                % self.__class__.__name__
            )
    
            return self.serializer_class
    Copyfrom rest_framework.generics import GenericAPIView
    # 利用GenericAPIView实现单查群查
    class CarGenericAPIView(GenericAPIView):
        # 配置queryset
        queryset = models.Car.objects.filter(is_delete=False).all()
        # 配置序列化类
        serializer_class = CarModelSerializer
    
        # url有名分组的传递关键字参数的key: car_pk = kwargs.get('pk')
        lookup_url_kwarg = 'pk'
        # 进数据库查询的筛选字段: models.Car.objects.filter(pk=car_pk).first
        lookup_field = 'pk'
    
        # 群查
        def get(self, request, *args, **kwargs):
             car_query = self.get_queryset()
             serializer_obj = self.get_serializer(instance=car_query, many=True)
             return APIResponse(results=serializer_obj.data)
    
        # 单查
        def get(self, request, *args, **kwargs):
            car_obj = self.get_object()
            serializer_obj = self.get_serializer(instance=car_obj)
            return APIResponse(results=serializer_obj.data)
    

    mixin视图工具类

    • 视图工具类都是基于GenericAPIView来使用的, 因此我们的视图类都要先继承GenericAPIVIew
    • 五个工具类, 六个方法
    Copy"""
    1.RetrieveModelMixin
        retrieve方法: 单查
        
    2.ListModelMixin
        list方法: 群查
        
    3.CreateModelMixin
        create方法: 单增
        
    4.UpdateModelMixin
        update方法: 整体单改
        partial_update方法: 局部单改
        
    5.DestroyModelMixin
        destory方法: 单删
    """
    
    from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, 
        UpdateModelMixin
    
    
    # mixin视图工具类
    class CarReadModelGenericAPIView(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericAPIView):
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = CarModelSerializer
        lookup_url_kwarg = 'pk'
    
        # 群查: ListModelMixin下面的list方法
        def get(self, request, *args, **kwargs):
             return self.list(request, *args, **kwargs)
    
        # 单查: RetrieveModelMixin下面的retrieve方法
        def get(self, request, *args, **kwargs):
            return self.retrieve(request, *args, **kwargs)
    
        # 单增: CreateModelMixin下面的create方法
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    

    generics工具视图类

    • 九种组合
    Copy"""
    1.都继承了GenericAPIView
    2.继承了不同组合的Mixin
    3.不同的组合实现了get, post, put, patch, delete方法
    4.我们自需要配置queryset, serializer_class, lookup_url_kwarg, lookup_field几个类属性即可
    """
    
    from rest_framework.generics import RetrieveAPIView, ListAPIView, RetrieveUpdateDestroyAPIView
    
    
    # 单查: RetrieveAPIView下面的get方法
    class CarRetrieveAPIView(RetrieveAPIView):
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = CarModelSerializer
        lookup_url_kwarg = 'pk'
    
    
    # 群查: ListAPIView下面的get方法
    class CarListAPIView(ListAPIView):
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = CarModelSerializer
    
    
    # 单查, 整体单改, 局部单改, 单删
    class CarRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView):
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = CarModelSerializer
    

    viewsets视图集

    • ViewSetMixin
    Copy"""
    视图集都继承ViewSetMixin, 该类重写as_view方法, 相比于APIView的as_view方法(局部禁用csrf), 多了一个参数: actions, as_view(actions={'get': 'list'}), 通过__getattr__和__setattr__给视图类增加了get属性, 该属性指向list方法, 因此向该url提交get请求, 就会触发视图类下面的list方法
    ViewSetMixin只提供as_view方法, 没有写dispatch方法, 也没有继承任何类, 因此我们是不能直接拿来用的
    
    """
    class ViewSetMixin:
        def as_view(cls, actions=None, **initkwargs):
        
            ...
    
            # actions: {'get': 'list'}
            for method, action in actions.items(): 
                # 通过反射获取视图类下面的list方法
                handler = getattr(self, action)
                # 将list方法赋值给get属性
                setattr(self, method, handler)
    
            ... 
    
            return csrf_exempt(view)
    
    • GenericViewSet和ViewSet两个视图集基类
    Copy""" 
    这两货啥都没写, 就是多继承了一个类, 用来提供dispatch方法
    """
    
    # 该分支满足的接口与资源Model类关系不是特别密切:登录接口、短信验证码接口
    class ViewSet(ViewSetMixin, views.APIView):
        pass
    
    # 该分支严格满足资源接口
    class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
        pass
    
    • ReadOnlyModelViewSet和ModelViewSet两个视图集子类
    Copy"""
    这两货好像也是啥都没干, 就行进行了Mixin视图工具类和GenericAPIView的组装
    """
    
    class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                               mixins.ListModelMixin,
                               GenericViewSet):
        pass
    
    
    class ModelViewSet(mixins.CreateModelMixin,
                       mixins.RetrieveModelMixin,
                       mixins.UpdateModelMixin,
                       mixins.DestroyModelMixin,
                       mixins.ListModelMixin,
                       GenericViewSet):
        pass
    

    路由配置

    Copyurlpatterns = [
        url(r'^v4/car/$', views.CarGenericViewSet.as_view({
            'get': 'list',
            'post': 'create',
            'put': 'many_update',
            'patch': 'many_partial_update',
            'delete': 'many_destroy'
        })),
    
        url(r'^v4/car/(?P<pk>d+)/$', views.CarGenericViewSet.as_view({
            'get': 'retrieve',
            'put': 'update',
            'patch': 'partial_update',
            'delete': 'destroy'
        }))
    
    ]
    Copy# DRF的路由组件
    from rest_framework.routers import SimpleRouter
    
    # 生成SimpleRouter对象
    router = SimpleRouter()
    # 参数: 路由, 视图类, 资源名称
    router.register('v4/car', views.CarModelViewSet, basename='car')
    
    urlpatterns = [
        url(r'', include(router.urls))
    ]
    
  • 相关阅读:
    经纬度计算距离
    MS SQL 获取身份证年龄
    C# SpeechSynthesizer 使用
    mysql 获取字段括号里的内容
    C# 获取操作系统版本
    微信 小程序跳转到的H5页面,再跳转回跳小程序
    SQL 收缩日志
    SQL 获取表结构
    SQL Server 优化
    Snowflake
  • 原文地址:https://www.cnblogs.com/colacheng0930/p/12154439.html
Copyright © 2020-2023  润新知