zoukankan      html  css  js  c++  java
  • Django-视图组件

    Django REST framwork 提供的视图的主要作用:
    1.控制序列化器的执行(检验、保存、转换数据)
    2.控制数据库查询的执行

    一、两个视图基类

    先上结论:

    APIView:如果跟models没有关系(没有数据库相关操作),就继承它
    GenericAPIView:有关数据库操作,queryset 和serializer_class
    

    1.APIView

    继承了原生Django的View,需要我们自己写对应请求方法的代码,比如

    class BookAPIView(APIView):
        def get(self, request):
            book_list = models.Book.objects.all()
            ser = serializer.BookModelSerializer(book_list, many=True)
            return Response(ser.data)
    
        def post(self, request):
            ser = serializer.BookModelSerializer(data=request.data)
            if ser.is_valid():
                ser.save()
            	return Response(ser.data)
            return Response(ser.error)
        
    class BookDetailAPIView(APIView):
        def get(self, request, pk):
            book = models.Book.objects.get(id=pk)
            ser = serializer.BookModelSerializer(book)
            return Response(ser.data)
    
        def put(self, request, pk):
            book = models.Book.objects.get(id=pk)
            ser = serializer.BookModelSerializer(book, data=request.data)
            if ser.is_valid():
                ser.save()
            return Response('修改成功')
    
        def delete(self, request, pk):
            models.Book.objects.filter(id=pk).delete()
            return Response('删除成功')
    

    2.GenericAPIView

    继承了APIView,考虑到使用APIView时,当我们写多个类,变化的代码只有调用的myserializers类和自己的表模型,所以将变量提取了出来。

    queryset = models.Book.objects.all()
    serializer_class = serializer.BookModelSerializer
    get_queryset:获取配置的queryset
    get_object:单条记录查询时使用,路由中的分组字段必须是pk
    get_serializer:获取配置的序列化类    
    
    class BookGenericView(GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    
        def get(self, request, *args, **kwargs):
            obj = self.get_queryset()
            ser = self.get_serializer(obj, many=True)
            return Response(ser.data)
        def post(self, request, *args, **kwargs):
            ser=self.get_serializer(data=request.data)
            if ser.is_valid():
                ser.save()
            return Response('成功')
        
    class BookDetailGenericAPIView(GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    
        def get(self, request, *args, **kwargs):
            obj = self.get_object()
            ser = self.get_serializer(obj)
            return Response(ser.data)
    
        def put(self, request, *args, **kwargs):
            obj = self.get_object()
            ser = self.get_serializer(obj, data=request.data)
            if ser.is_valid():
                ser.save()
            return Response('修改成功')
    
        def delete(self, request, *args, **kwargs):
            # self.get_object().delete() 或者下面的方法
            self.queryset.filter(id=kwargs.get('pk')).delete()
            return Response('删除成功')
    

    二、五个视图扩展类

    当我们利用GenericAPIView类把变量提取出去后,会发现其实对于不同的接口我们其实内部代码是一样的,所以进行了封装,即把每个请求方法都提取出来,封装成单独的一个类。

    from rest_framework.mixins import ...
    CreateModelMixin:create方法创建一条
    DestroyModelMixin:destory方法删除一条
    ListModelMixin:list方法获取所有
    RetrieveModelMixin:retrieve获取一条
    UpdateModelMixin:update修改一条
    
    class BookGenericView(GenericAPIView,ListModelMixin,CreateModelMixin):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    
        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 BookDetailGenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    
        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 delete(self, request, *args, **kwargs):
            return self.destroy(request, *args, **kwargs)
    

    三、九个子类视图

    子类视图是对扩展类的进一步封装,因为我们上一部分还是有重复代码,既然这些请求方法进来之后,执行逻辑一样,那么我就再进一步封装。

    五个扩展类,分为群get,post,单get,put,delete。在我们常见类中,一般是群get,post一个类,另外三个方法一个类,所以各自组合,正好九种子类视图,即2+1,3+2+1,共有九种组合方式

    #9个子类视图(rest_framework.generics)
    CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
    DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
    ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
    UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
    RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
    
    
    ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
    RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
    RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
    RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
    

    以下为最全的方式九个子类视图比较灵活,可以任意组合

    from rest_framework.generics import ListCreateAPIView
    from rest_framework.generics import RetrieveUpdateDestroyAPIView
    
    class BookGenericView(ListCreateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    
    class BookDetailGenericAPIView(RetrieveUpdateDestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    

    四、视图集

    当我们已经封装到了子类视图时,就会发现,代码的重复又出现了,以上我们写的两个类其实代码一样,所以又进行了一次封装。一般情况下我们使用ModelViewSet或者ReadOnlyModelViewSet,但是视图集不仅仅包含这两个。

    from rest_framework.viewsets import ModelViewSet # 包含五种请求方法
    from rest_framework.viewsets import ReadOnlyModelViewSet # 只有查询,单记录查和群查
    
    class BookSetView(ModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookModelSerializer
    

    1. ViewSet

    继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

    ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。

    在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

    2.GenericViewSet

    使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView

    GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

    举例:

    from rest_framework.viewsets import GenericViewSet
    from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
    class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
        queryset = Student.objects.all()
        serializer_class = StudentModelSerializer
    

    url的定义

    urlpatterns = [
        path("students7/", views.Student4ViewSet.as_view({"get": "list", "post": "create"})),
        re_path("students7/(?P<pk>d+)/", views.Student4ViewSet.as_view({"get": "retrieve","put":"update","delete":"destroy"})),
    
    ]
    

    3.ModelViewSet

    继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

    4.ReadOnlyModelViewSet

    继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

    5.源码分析

    ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。因我们现在把所有动作都封装了,所以在单get和群get请求的时候会出现问题,因为两个都是get请求,且请求打到同一个类中,在这里,框架作者使用了非常巧妙的方法来解决这个问题。解决的方案是在路由里配上对应的方法。代码如下

    path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'})),
    re_path('^books_set/(?P<pk>d+)', views.BookSetView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    

    在原生的类中as_view方法肯定是不支持这种做法的,所以ModelViewSet一定重写了as_view()方法

    image-20201106151346879

    image-20201106151557963

    五、路由的使用

    一般如果使用了drf的视图类,那么都会配合路由组件一起使用,因为路由组件可以帮我们自动生成路由的路径

    1.路由组件的简单使用

    # 自动生成路由,以下两个使用较多
    SimpleRouter与DefaultRouter
    
    # 继承了ViewSetMixin的视图类,以后写路由,可以自动生成,写在urls.py中
    from rest_framework import routers
    # 实例化得到一个对象
    router = routers.SimpleRouter()
    # 注册进路由
    router.register('books', views.BookSetView)
    # 把自动生成的路由配置到urlpatterns中
    	-urlpatterns += router.urls  # 或者下面的方式
        -re_path(r'v1/', include(router.urls))  
        # 这里的v1指的是在生成的路径前都加上v1这个路径,比如原来的login,现在变成了v1/login
    

    2.配置路由的方式

    # 三种方式
    1.最原始的
    	-path('books/', views.BookAPIView.as_view()),
    2.ViewSetMixin的视图类
    	-path('books_set/', views.BookSetView.as_view({'get':'list','post':'create'}))
    3.ViewSetMixin的视图类
    -自动生成,上面讲的
    

    3.action

    -当自动生成路由的时候,由于视图类中还有其它方法,是无法自动生成路由的
    -加action装饰器:
    	-methods:什么请求方式会触发被装饰函数的执行
        -detail:是True是基于带id的路由生成的,如果是False,是基于不带id的路由生成的
    	-@action(methods=['get'], detail=True)
  • 相关阅读:
    Java学习笔记
    JSP/Servlet笔记
    JavaScript笔记
    JavaScript笔记
    JavaScript笔记 – 程序语法设计
    Mybatis笔记
    Mybatis笔记
    Mybatis笔记 – 关联查询
    Mybatis笔记 – Po映射类型
    Mybatis笔记
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066500.html
Copyright © 2011-2022 走看看