• 🍖drf 视图组件


    一.视图介绍

    1.Django REST framwork 提供的视图的主要作用:

    • 控制序列化器的执行 : 检验, 保存, 转换数据
    • 控制数据库查询的执行

    二 .2 个视图基类

    REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写

    APIView

    1.APIView 与 View

    • APIView是REST framework 提供的所有视图的基类, 继承自Django的View父类

    • APIView 相比较与 View, 它对Django原生的 request 对象进行了处理转成了 DRF 的 request对象

    • 并重写了 dispatch 方法, 在路由分发之前会对请求进行身份认证, 权限检查, 频率控制

    • 重写了View中通过本次请求的方式动态的反射到自定义继承APIView类实例化的对象中定义的请求方法

    • 设置全局异常处理

    • 处理完毕异常以后使用的是 drf 的 response 对象对请求响应

    2.示例

    • APIView中仍以常规的类视图定义方法来实现get( ) 、post( ) 或者其他请求方式的方法

    • 导入方式 : from rest_framework.views import APIView

    • models.py

    from django.db import models
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32, null=True)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    
    • serializers.py
    from mydrf import models  # 项目名:mydrf
    from rest_framework import serializers
    
    class PublishSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Publish
            fields = "__all__"
    
    • views.py
    from mydrf import models
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from mydrf.serializers import PublishSerializer
    
    class PublishView(APIView):
        # 获取所有书
        def get(self, request):
            publish_qs = models.Publish.objects.all()
            # 有多条数据的时候一定要添加many=True
            publish_ser = PublishSerializer(instance=publish_qs, many=True)  
            return Response(publish_ser.data)
    
        # 新增数据
        def post(self, request):
            publish_ser = PublishSerializer(data=request.data)
            if publish_ser.is_valid():
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                # publish_ser.errors
                return Response("error")
    
    
    class Publish2View(APIView):
        # 获取一条
        def get(self, request, id):
            publish_obj = models.Publish.objects.filter(pk=id).first()
            publish_ser = PublishSerializer(instance=publish_obj)
            return Response(publish_ser.data)
    
        # 修改数据
        def put(self, request, id):
            publish_obj = models.Publish.objects.filter(pk=id).first()
            publish_ser = PublishSerializer(instance=publish_obj, data=request.data)
            if publish_ser.is_valid():
                publish_ser.save()
                return Response(publish_ser.data)
            else:
                return Response(publish_ser.errors)
    
        # 删除数据
        def delete(self, request, id):
            # 直接删除数据,拿到影响条数的一个列表
            rows = models.Publish.objects.filter(pk=id).delete()
            # 取出来判断一下
            if rows[0] > 0:
                return Response('数据删除成功!')
            else:
                return Response('数据不存在!')
    
    • urls.py
    path('publish/', views.PublishView.as_view()),
    path('publish/<int:id>', views.Publish2View.as_view()),
    

    GenericAPIView (通用视图类)

    1.通用视图类介绍

    • 继承自APIVIew, 主要增加了操作序列化器数据库查询的方法, 作用是为下面Mixin扩展类的执行提供方法支持; 通常在使用时, 可搭配一个或多个Mixin扩展类

    • 导入方式 : from rest_framework.generics import GenericAPIView

    2.提供关于序列化器的属性和方法

    • 属性
    属性 作用
    queryset (常用) 需要序列化的查询集
    serializer_class (常用) 指定使用的序列化器
    pagination_class 分页控制类
    filter_backends 过滤控制后端
    lookup_field 查询单一数据库对象时使用的条件字段,默认为’pk’
    ... ...
    • 方法
    方法 作用
    get_queryset( ) (常用) 获取QuerySet查询集
    get_object( ) (常用) 获取一条数据对象
    get_serializer( ) 返回序列化器对象,可以其他视图或扩展类使用
    get_serializer_class 返回序列化器类,默认返回serializer_class,可以重写
    ... ...

    3.示例

    • models.py 文件不变
    • serializers.py 文件不变
    • views.py
    from mydrf.serializers import PublishSerializer
    from rest_framework.generics import GenericAPIView
    
    # 查看所有, 新增一条
    class PublishListCreateView(GenericAPIView):
        queryset = models.Publish.objects.all()  # 需要要序列化的数据
        serializer_class = PublishSerializer     # 指定序列化类
    
        def get(self, request):
            query_set = self.get_queryset()      # 获取要序列化的数据
            serializer = self.get_serializer(query_set, many=True)  # 获取序列化之后得到的对象
            return Response(serializer.data)
    
        def post(self, request):
            serializer = self.get_serializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            else:
                return Response(serializer.error)
    
    # 查一条, 改, 删
    class PublishUpdateDestroyRetrieveView(GenericAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
        def get(self, request, *args, **kwargs):
            publish_obj = self.get_object()       # 获取要序列化的单条数据
            serializer = self.get_serializer(publish_obj)  # 获取序列化之后得到的对象
            return Response(serializer.data)
    
        def put(self, request, *args, **kwargs):
            publish_obj = self.get_object()
            serializer = self.get_serializer(instance=publish_obj, data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            else:
                return Response(serializer.error)
    
        def delete(self, request, *args, **kwargs):
            rows = self.get_object().delete()
            if rows[0] > 0:
                return Response('')
            else:
                return Response('该数据不存在!')
    
    • urls.py
    path('publish1/', views.PublishListCreateView.as_view()),
    path('publish1/<int:pk>', views.PublishUpdateDestroyRetrieveView.as_view()),
    

    查询条件使用的条件字段是有 lookup_field 属性来控制的, 默认是 pk, 可以修改

    三.5 个视图扩展类

    1.五个视图扩展类

    扩展类提供方法用途
    ListModelMixinlist()获得多条数据对象
    CreateModelMixincreate()新建单一数据对象
    RetrieveModelMixinretrieve()获得单一数据对象
    UpdateModelMixinupdate()更新一条数据
    DestroyModelMixindestroy()删除单⼀一对象

    2.作用 :

    • 提供了几种后端视图 (对数据资源进行曾删改查) 处理流程的实现
    • 如果需要编写的视图属于这五种, 则视图可以通过继承相应的扩展类来复用代码, 减少自己编写的代码
    • 这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法

    3.示例

    • models.py 文件不变
    • serializers.py 文件不变
    • views.py
    from rest_framework.generics import GenericAPIView    # 视图基类
    from rest_framework.mixins import CreateModelMixin    # 增
    from rest_framework.mixins import DestroyModelMixin   # 删
    from rest_framework.mixins import UpdateModelMixin    # 改
    from rest_framework.mixins import RetrieveModelMixin  # 查一条
    from rest_framework.mixins import ListModelMixin      # 查所有
    
    # 获取所有, 新增一条
    class PublishListCreateView2(GenericAPIView, CreateModelMixin, ListModelMixin):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request):
            return self.create(request)
    
    # 获取一条, 修改, 删除
    class PublishDeUpReView2(GenericAPIView, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
        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)
    
    • urls.py
    path('publish2/', views.PublishListCreateView2.as_view()),
    path('publish2/<int:pk>', views.PublishDeUpReView2.as_view()),
    

    四.9 个视图子类

    1.九个视图子类

    子类 提供方法 继承自
    CreateAPIView 提供 post 方法 GenericAPIView、CreateModelMixin
    ListAPIView 提供 get 方法 GenericAPIView、ListModelMixin
    RetireveAPIView 提供 get 方法 GenericAPIView、RetrieveModelMixin
    DestoryAPIView 提供 delete 方法 GenericAPIView、DestoryModelMixin
    UpdateAPIView 提供 put 和 patch 方法 GenericAPIView、UpdateModelMixin
    ListCreateAPIView 提供 get、post方法 GenericAPIView、ListModelMixin、CreateModelMixin
    RetrieveUpdateAPIView 提供 get、put、patch方法 GenericAPIView、RetrieveModelMixin、UpdateModelMixin
    RetrieveDestroyAPIView 提供 get、put、patch方法 GenericAPIView、RetrieveModelMixin、DestoryModelMixin
    RetrieveUpdateDestoryAPIView 提供 get、put、patch、delete方法 GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

    2.示例

    • models.py 文件不变
    • serializers.py 文件不变
    • views.py
    from rest_framework.generics import CreateAPIView      # 新增
    from rest_framework.generics import ListAPIView        # 查看所有
    from rest_framework.generics import ListCreateAPIView  # 查看所有新增一个
    from rest_framework.generics import RetrieveAPIView    # 查看一个
    from rest_framework.generics import DestroyAPIView     # 删除一个
    from rest_framework.generics import UpdateAPIView      # 修改一个
    from rest_framework.generics import RetrieveUpdateAPIView  # 查看一个,修改一个
    from rest_framework.generics import RetrieveDestroyAPIView  # 查看一个,删除一个
    from rest_framework.generics import RetrieveUpdateDestroyAPIView  # 查看一个,修改一个,删除一个
    
    
    # class PublishView3(CreateAPIView,ListAPIView):  # 或者下面写法,可以自行组合
    class PublishView3(ListCreateAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
    
    # class PublishReDeUpView3(RetrieveAPIView, DestroyAPIView, UpdateAPIView): # 或者下面写法
    class PublishReDeUpView3(RetrieveUpdateDestroyAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
    • urls.py
    path('publish3/', views.PublishView3.as_view()),
    path('publish3/<int:pk>',views.PublishDeUpReView2.as_view()),
    

    五.视图集 (ViewSet)

    0.为什么要有视图集

    • 不同的视图集继承了不同的视图基类、视图子类或者视图扩展类, 我们使用视图集可以更加方便的操作数据

    • 在没有视图集之前, DRF五大接口帮我们实现数据操作 : get_one, get_list, post, put, delete

    • 我们可以写一个类, 然后继承GenericAPIView的九个视图子类来实现五个接口

    • 但是出现的问题是 : 查询所有使用 get 方法, 查询一条也是使用 get 方法, 但是在Python中, 同一个类中不能有相同的方法名

    • 于是DRF的作者在这个类中不再实现get( )、post( )等方法, 而是将它们映射成对应的 action 行为

    • 查询所有的 get( ) 方法映射成 list( ), 查询一条的 get( ) 方法映射成 retrive( ), 这就是视图集的由来

    1.视图集的作用

    • 使用视图集可以将一系列逻辑相关的动作放到一个类中
    list()      # 提供一组数据
    retrieve()  # 提供单个数据
    create()    # 创建数据
    update()    # 保存数据
    destory()   # 删除数据
    
    • ViewSet视图集类不再实现get( )、post( )等方法,而是实现动作 action 如 : list( ) 、create( ) 等
    • 视图集只在使用as_view( )方法的时候,才会将action动作与具体请求方式相互映射

    2.常用的视图集父类

    ViewSet

    • 继承自 : APIViewViewSetMixin
    • 作用 : 与APIView基本类似,提供了身份认证、权限校验、流量管理等
    • ViewSet主要通过继承ViewSetMixin来实现在调用as_view( )时传入字典的映射处理工作
    • 缺点 : 在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法

    GenericViewSet

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

    ModelViewSet

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

    ReadOnlyModelViewSet

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

    3.示例

    • views.py
    from rest_framework.viewsets import ModelViewSet  # 继承GenericViewSet + 五个接口都有
    from rest_framework.viewsets import ReadOnlyModelViewSet  # 继承GenericViewSet + 只有读两个接口
    from rest_framework.viewsets import GenericViewSet  # 继承GenericAPIView与ViewSetMixin
    from rest_framework.viewsets import ViewSet  # 继承的APIView与ViewSetMixin
    from rest_framework.viewsets import ViewSetMixin  # 提供修改路由中ac_view()类方法的actions参数
    
    
    class PublishView4(ModelViewSet):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
    
    • views.py
    # 需要书写方法映射关系
    path('publish4/', views.PublishView4.as_view(actions={'get':'list','post':'create'})),
    path('publish4/<int:pk>', views.PublishView4.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),
    
    • 视图集在使用as_view() 方法的时候需要书写方法与action的映射关系, 因为ViewSetMixin重写了父类的as_view()方法, 在书写路由的时候就需要以上面的方式书写

    • 在继承ViewSetMixin的时候一定要将其放在最左边, 这样在调用as_view()方法的时候才会先调用ViewSetMixin中的as_view()方法

    • 上面的四种常用视图集都直接或间接的继承了ViewSetMixin

    4.视图集中定义附加的 action 动作

    在视图集中,除了上述默认的方法动作外,还可以添加自定义动作

    • views.py
    class PublishView5(GenericViewSet):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
        # 自定义的 action
        def get_xxx(self,request):
            query_set = self.get_queryset()
            serializer = self.get_serializer(query_set,many=True)
            return Response(serializer.data)
    
    • urls.py
    path('publish5/', views.PublishView5.as_view(actions={'get': 'get_xxx'})),
    

    5.action 属性

    在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个

    class PublishView5(GenericViewSet):
        queryset = models.Publish.objects.all()
        serializer_class = PublishSerializer
        # 自定义的 action
        def get_xxx(self,request):
            query_set = self.get_queryset()
            serializer = self.get_serializer(query_set,many=True)
            print(self.action)  # get_xxx
            return Response(serializer.data)
    

    六.DRF视图关系继承图

    ps : 在 Pycharm 中可以鼠标右击一个视图类------>Diagrams------>Show Diagrams 来查看这个类的继承关系

    image-20210415183341863

    • 视图提供的相应方法图
    DRF视图关系图
  • 相关阅读:
    学习了数据库中text类型的查找
    通过 .NET Framework 中的 XPath 和 XSLT API 方便地操作 XML 数据
    Windows服务器下用IIS Rewrite组件为IIS设置伪静态方法
    C# 文件压缩与解压(ZIP格式)
    用SharpZipLib来压缩和解压文件(转载)
    Community Server专题二:体系结构(转载)
    在ASP.NET中如何实现和利用URL重写
    Community Server专题一:概述Community Server(转载)
    C#委托之个人理解
    在ASP.NET中实现Url Rewriting
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14670491.html
Copyright © 2020-2023  润新知