• 三,APIView、GenericAPIView、Mixins总结


    概述

    APIView是DRF的视图层中最基本的类,它相当于Django中的View类,其他视图类都是通过继承APIView实现的。

    GenericAPIView继承于APIView,在其父类的基础上为列表视图和详情视图添加了常用的行为。

    Mixins提供了一些基本视图行为的操作方法,如提供的list()方法将返回查询集,等等。因为Python多继承的特性,因此,在定义视图时可以将GenericAPIView和Mixins进行灵活的组合。而DRF中就提供了许多这样的类可以供我们完成所有所需的View。

    1.APIView

    在DRF中提供了APIView,继承于Django的View,作为最基本的类视图,处理用户的请求并返回响应。和View相比,APIView有如下特点:

    1.传递给处理方法的请求是DRF的Request实例,而不是Django的HttpRequest实例;
    2.响应并返回的是DRF的Response对象,而不是Django的HttpResponse对象;
    3.任何APIException异常都会被捕获并调制到适当的响应中;
    4.会对接收的请求进行身份认证和权限的检查。
    和使用View类似,使用APIView时,接收的请求会被dispatch到对应的方法中,如get()、post()……此外,还可以设置许多属性来控制API各个方面的策略。

    使用APIView时需要导入其所在模块:

    from rest_framework.views import APIView

    基本的使用APIView方式举例如下:

    class SnippetList(APIView):
    
        # 处理GET请求
        def get(self, request, format=None):
    
            snippet = Snippet.objects.all()
            serializer = SnippetSerializer(snippet, many=True)
            return Response(serializer.data)
    
        # 处理POST请求
        def post(self, request, format=None):
            serializer = SnippetSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
    

      

    1.1.常用属性

    .authentication_classes

    该属性用于指定当前View endpoint的身份验证类,如:

    from rest_framework.authentication import TokenAuthentication
    
    
    class TestView(APIView):
    
        authentication_classes = (TokenAuthentication,)
        # ......

    使用authentication_classes设置的身份验证类将仅仅对该View验证有效,如果需要对整个项目有效,则需要在settings.py配置文件中进行设置:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            # ......
            'rest_framework.authentication.authentication.TokenAuthentication',
        )
    }


    DEFAULT_AUTHENTICATION_CLASSES也是身份验证类列表的默认值。

    .permission_classes

    该属性用于指定当前View endpoint的权限类列表,如:

    from rest_framework import permissions
    class SnippetList(APIView):
        # ...
        permission_classes = (permissions.IsAuthenticatedOrReadOnly,permissions.IsAuthenticated,permissions.IsAdminUser)
        # ...

    如果不指定该属性,则默认使用settings.DEFAULT_PERMISSION_CLASSES中指定的权限列表。

    APIView是DRF中所有View的基类,也是DRF中视图层的基础,但APIView并不是重点,重点是下面的GenericAPIView和Mixins以及两个混合组成的许多类。

    2.GenericAPIView

    GenericAPIView继承于APIView,为常用的列表视图和详细视图提供了一些操作属性方法。

    使用GenericAPIView时需要导入对应模块:

    from rest_framework import generics

    其基本使用方式如下:

    from .serializers import SnippetSerializer
    from .models import Snippet
    # Create your views here.
    
    
    class Show(generics.GenericAPIView):
    
        # 指定序列化类
        serializer_class = SnippetSerializer
        # 指定QuerySet对象
        queryset = Snippet.objects.all()
    
        def get(self, request):
            return Response("hello world...")
    
        def post(self, request):
            return Response(request.data)

    2.1.常用属性和方法

    .queryset

    指定要显示的Model对象的QuerySet对象(查询集),用于列表视图中。在GenericAPIView中必须指定该属性或者重写get_queryset()方法。

    .serializer_class

    指定要显示的Model对象的Serializer对象,在GenericAPIView中必须指定该属性或者重写get_serializer()方法。

    .lookup_field

    指定用于查找单个Model实例的Model字段,默认为pk.

    .lookup_url_kwarg

    指定用于Model查找的url关键字参数,如果未设置,则默认使用与lookup_field的值。

    .pagination_class

    指定列表视图中用于分页的分页类列表,可以对响应列表进行分页。默认使用配置文件中DEFAULT_PAGINATION_CLASS的值。

    .filter_backends

    指定用于过滤查询集的过滤器后端类列表。 默认使用为DEFAULT_FILTER_BACKENDS设置的值。

    .get_queryset(self)

    返回用于列表视图的查询集,默认返回queryset属性指定的查询集。

    NOTE: 
    应始终使用此方法而不是直接访问self.queryset,因为self.queryset仅被评估一次,然后将结果进行缓存用于所有后续请求。

    .get_object(self)

    返回用于详情视图中的Model对象实例,默认使用lookup_field字段过滤QuerySet中的数据。

    .get_serializer()

    返回用于Model序列化的Serializer类,默认返回serializer_class属性的值,该方法可以用来动态指定一个序列化类。

    3.Mixin

    通常GenericAPIView不会单独使用,因为它相比APIView,仅仅提供了一些公共的用于列表视图和详情视图的属性和方法,GenericAPIView需要和Mixins组合使用。

    Mixin类中提供了许多用于对视图进行操作的方法,这些操作方法无须我们自己实现就可以使用了。比如,ListModelMixin提供了一个list()方法用于将Model的查询集响应给客户端,因此可以用于列表视图的get()中:

    class show(generics.GenericAPIView,mixins.ListModelMixin):
    
        serializer_class = SnippetSerializer
        queryset = Snippet.objects.all()
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)

    相比使用APIView,简化了非常多的操作。

    使用Mixins需要导入其所在模块:

    from rest_framework import mixins

    下面对常用Mixins类及其功能进行下总结。

    3.1.ListModelMixin

    该类提供了一个.list(request, *args, **kwargs)方法,用于列出查询集QuerySet。如果queryset被填充,则响应码为200,并将查询集序列化作为响应体响应给客户端。

    3.2.CreateModelMixin

    该类提供一个.create(request, *args, **kwargs)方法,用于创建并保存一个新的Model实例,因此用在POST请求中,和post()方法组合使用。如果Model实例创建成功,则响应码为201 Created ,并将对象序列化后作为响应体响应给客户端;如果Model实例创建失败,则响应码为401(Bad Request),并将错误信息作为响应体。

    3.3.RetrieveModelMixin

    该类提供一个retrieve(request, *args, **kwargs)方法,用于检索并返回一个现有的Model实例。如果能够检索到对象,则返回200 OK响应,并将对象序列化后作为响应体输出,否则返回404 Not Found响应。

    3.4.UpdateModelMixin

    该类提供一个update(request, *args, **kwargs)方法,用于更新并保存现有的Model对象。因此用在PUT请求中,和put()方法组合使用。如果更新成功,则返回200 OK响应,并将对象序列化后作为响应体输出,否则返回400 Bad Request响应。

    3.5.DestroyModelMixin

    该类提供一个.destroy(request, *args, **kwargs)方法,用于删除一个已存在的Model实例。如果删除成功返回204 No Content响应,否则返回404 Not Found响应。

    以上方法无须我们再进行实现,直接使用即可,如以下示例:

    class SnippetDetail(mixins.RetrieveModelMixin,
                        mixins.UpdateModelMixin,
                        mixins.DestroyModelMixin,
                        mixins.CreateModelMixin,
                        generics.GenericAPIView):
        queryset = Snippet.objects.all()
        serializer_class = SnippetSerializer
        # get,put,delete方法是GenericAPIView中提供
        # retrieve,update,destory方法由Mixin类视图提供
        # 二者可以灵活的结合
        def get(self, request, *args, **kwargs):
            return self.list(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)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    

      

    4.常用具体通用视图

    在DRF中,除了提供Mixin类之外,还提供了GenericAPIView和Mixins的组合View类,这些类称为具体通用视图。因此我们不需要只需要具体通用视图就可以实现我们所需的功能,如:

    from rest_framework import generics
    
    class show(generics.ListCreateAPIView):
    
        serializer_class = SnippetSerializer
        queryset = Snippet.objects.all()

    在这个示例中,ListCreateAPIView继承自GenericAPIView, ListModelMixin, CreateModelMixin这三个类,并且内部已经将对应请求方法和操作方法进行了实现,我们只需要指定一些属性即可,无须再写get(),post()请求方法逻辑。

    下面是一些常用的具体通用视图。
    使用这些类时需要导入所在模块:

    from rest_framework import generics

    4.1.ListCreateAPIView

    父类:GenericAPIView,  mixins.ListModelMixin, mixins.CreateModelMixin
    特点:已提供了get()、put()方法处理。

    4.2.RetrieveUpdateDestroyAPIView

    父类:GenericAPIView,  mixins.RetrieveModelMixin,  mixins.UpdateModelMixin,  mixins.DestroyModelMixin
    特点:已提供了get()、put()、patch()、destory()方法处理。

    4.3.CreateAPIView

    父类:GenericAPIView, mixins.CreateModelMixin

    特点:已提供了post()方法处理。

    4.4.ListAPIView

    父类:GenericAPIView, mixins.ListModelMixin

    特点:已提供了get()方法处理。

    4.5.RetrieveAPIView

    父类:GenericAPIView, mixins.RetrieveModelMixin

    特点:已提供了get()方法处理。

    4.6.DestroyAPIView

    父类:GenericAPIView, mixins.DestroyModelMixin,

    特点:已提供了delete()方法处理。

    4.7.UpdateAPIView

    父类:GenericAPIView, mixins.UpdateModelMixin,

    特点:已提供了put(), patch()方法处理。

    4.8.RetrieveDestroyAPIView

    父类:GenericAPIView, mixins.RetrieveModelMixin,mixins.DestroyModelMixin,

    特点:已提供了get(), delete()方法处理。

    4.9.RetrieveUpdateDestroyAPIView

    父类:GenericAPIView, mixins.RetrieveModelMixin,mixins.DestroyModelMixin,mixins.UpdateModelMixin

    特点:已提供了get(), delete(), put(), putch()方法处理。

    其他具体通用视图,还请参考官方文档.

    5.重构View示例

    现在,利用以上View内容以及Django中的函数视图等内容,从函数视图开始,一步步对视图进行重构,看看其简化的过程。

    Step1.最初的函数视图

    # 列表视图
    @api_view(['GET', 'POST'])
    def student_list(request):
    
        # 处理GET请求
        if request.method == 'GET':
    
            student = Student.objects.all()
            serializers = StudentSerializer(student, many=True)
            return Response(serializers.data)
    
        # 处理POST请求
        if request.method == 'POST':
            serializer = StudentSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(status=status.HTTP_400_BAD_REQUEST)
    
    
    # 详情视图
    @api_view(['GET', 'POST'])
    def student_detail(request, pk):
        if request.method == 'GET':
    
            student = Student.objects.get(pk=pk)
            serializer = StudentSerializer(student)
            return Response(serializer.data)
    
        if request.method == 'POST':
    
            serializer = StudentSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(status=status.HTTP_400_BAD_REQUEST)
    

      

    Step2.将函数视图用APIView替换

    现在通过APIView进行重构,可以定义请求对应的get()方法和post()方法,重构后如下所示:

    from rest_framework.response import Response
    from hello.models import Student
    from hello.serializers import StudentSerializer
    from rest_framework import status
    from rest_framework import views
    
    # 列表视图
    class StudentList(views.APIView):
    
        # GET请求
        def get(self,request):
            student = Student.objects.all()
            serializer = StudentSerializer(student,many=True)
            return Response(serializer.data)
    
        # POST请求
        def post(self, request):
    
            serializer = StudentSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
    
    
    # 详情视图
    class StudentDetail(views.APIView):
    
        def get(self, request, pk):
            student = Student.objects.get(pk=pk)
            serializer = StudentSerializer(student)
            return Response(serializer.data)
    
        def post(self, request):
            serializer = StudentSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data)
            return Response(serializer.data, status=status.HTTP_400_BAD_REQUEST)
    

      

    Step3.GenericAPIView+Mixins替换APIView


    GenericAPIView相比APIView,提供了部分属性;Mixins提供了许多用于对视图进行操作的方法:

    from rest_framework.response import Response
    from hello.models import Student
    from hello.serializers import StudentSerializer
    from rest_framework import status
    from rest_framework import generics
    from rest_framework import mixins
    from django.http import Http404
    
    
    class StudentList(generics.GenericAPIView, minxins.ListModelMixin, mixins.CreateModelMixin):
    
        # 指定序列化类
        serializer_class = StudentSerializer
        # 执行Model对象查询集
        queryset = Student.objects.all()
        # 如果不对query_set的值进行修改,没有必要重写该方法
        def get_queryset(self):
            return Student.objects.all()
    
        def get(self, request):
            return self.list(request)
    
        def post(self, request):
            return self.create(request)
    
    # 详情视图
    class StudentDetail(generics.GenericAPIView,
                        mixins.RetrieveModelMixin):
    
        def get(self, request, *args, **kwargs):
            return self.retrieve(self, request, *args, **kwargs)
    

      

    Step4.使用具体通用视图替换GenericAPIView+Mixins

    from hello.models import Student
    from hello.serializers import StudentSerializer
    from rest_framework import generics
    
    # 列表视图
    class StudentList(generics.ListCreateAPIView):
    
        serializer_class = StudentSerializer
        queryset = Student.objects.all()
    
    
    # 详情视图
    class StudentDetail(generics.RetrieveUpdateDestroyAPIView):
    
        queryset = Student.objects.all()
        serializer_class = StudentSerializer
    

      

    通过具体通用视图,两行代码就搞定。

    总结
    DRF中提供了这么多View,但无非就是从views.View这个基类,通过继承、mixin实现而已。因此,在学习这些类时,不必死记硬背,而是通过其继承结构、实现源码,了解明白它的作用和使用方式,以及和mixin的混合使用,这样才可以更好的使用DRF中的各种View。

  • 相关阅读:
    不要盲目使用新技术,说的就是你,asp.net core!
    MySQL5.7官方文档翻译-innodb事务模型与锁
    Springboot+JPA下实现简易爬虫--爬取豆瓣电视剧数据
    volatile型变量语义讲解一 :对所有线程的可见性
    VAE《放肆》如约而至: 递归算法 + Stream函数式编程 + Lambda相遇实现树状结构
    设计模式(4)——单例模式的学习及其六大战将
    微服务分布式电商项目学习笔记(三)---- docker介绍安装以及使用docker安装软件(2020/7/10)
    杭州生鲜配送管理系统_关于猪肉分割分拆与水果分等级包装的库存与成本计算的若干思考与系统界面设计_升鲜宝供应链管理系统_15382353715
    杭州生鲜配送管理系统_升鲜宝_强烈要求蔬东坡软件公司给出书面的道歉。蔬东坡软件公司利用莫须有的事实来诋毁与打击同行,不道德的竞争手段,来获取市场(一)
    杭州生鲜配送管理系统_升鲜宝_强烈要求蔬东坡软件公司给出书面的道歉。记蔬东坡软件公司利用莫须有的事实来诋毁与打击同行,不道德的竞争手段,来争取市场(三)
  • 原文地址:https://www.cnblogs.com/yoyo1216/p/10443530.html
Copyright © 2020-2023  润新知