• DRF 视图组件


    DRF 视图组件

    ModelSerializer序列化器实战

    DRF框架提供了很多通用的视图基类与扩展类,上篇使用的APIView是比较偏Base的,视图的使用更加简化了代码,这里介绍一下其他视图的用法

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

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

    先来看看这其中的人情世故:两个视图基本类,五个扩展类,九个视图子类,视图集方法,视图集··

    img

    视图组件大纲

    两个视图基本类

    导入

    from rest_framework.views import APIView
    from rest_framework.generics import GenericAPIView
    
    • APIView:DRF最顶层视图类
    • GenericAPIView:DRF通用视图类

    五个扩展类

    扩展类不是视图类,没有集成APIView,需要配合GenericAPIView使用,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法

    主要是用来对数据进行增删改查

    导入

    from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
    
    • CreateModelMixin
    • ListModelMixin
    • DestroyModelMixin
    • RetrieveModelMixin
    • UpdateModelMixin

    九个子类视图

    导入

    from rest_framework.generics import  CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView
    

    视图子类其实可以理解为GenericAPIView通用视图类和Mixin扩展类的排列组合组成的,底层事通过封装和继承来写

    • CreateAPIView

      提供 post 方法
      继承自: GenericAPIView、CreateModelMixin
      
    • ListAPIView

      提供 get 方法
      继承自:GenericAPIView、ListModelMixin
      
    • DestroyAPIView

      提供 delete 方法
      继承自:GenericAPIView、DestoryModelMixin
      
    • RetrieveAPIView

      提供 get 方法
      继承自: GenericAPIView、RetrieveModelMixin
      
    • UpdateAPIView

      提供 put 和 patch 方法
      继承自:GenericAPIView、UpdateModelMixin
      
    • ListCreateAPIView

      提供get 和 post方法
      继承自:ListModelMixin、CreateModelMixin、GenericAPIView
      
    • RetrieveUpdateAPIView

      提供 get、put、patch方法
      继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
      
    • RetrieveDestroyAPIView

      提供:get、delete方法
      继承自:RetrieveModelMixin、DestroyModelMixin、GenericAPIView
      
    • RetrieveUpdateDestroyAPIView

      提供 get、put、patch、delete方法
      继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
      

    视图集

    导入

    from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
    

    常用视图集父类#

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

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

    • ViewSet:继承自APIView与ViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典({'get':'list'})的映射处理工作。

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

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

    魔法类#

    • ViewSetMixin:控制自动生成路由

    一览表

    image

    DRF中视图的“七十二变”

    第一层是继承APIView写,第二层基于基于GenericAPIView写,第三层基于GenericAPIView+五个扩展类写,第四层通过九个视图子类来写,第五层是通过ViewSet写

    ps:第几层是我意淫出来的词不要介意~,一层更比一层牛,欲练此功必先自宫!!!

    第一层:基于APIview的五个接口

    class BookView(APIView):
        def get(self, requets):
            # 序列化
            book_list = models.Book.objects.all()
            # 序列化多条数据many=True
            ser = serializer.BookSerializer(instance=book_list, many=True)
            return Response(ser.data)
    
        def post(self, request):
            # 获取反序列化数据
            ser = serializer.BookSerializer(data=request.data)
            if ser.is_valid():
                # 校验通过存入数据库,不需要重写create方法了
                ser.save()
                return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
            # 校验失败
            return Response({'code': 101, 'msg': '校验未通过', 'error': ser.errors})
    
    
    class BookViewDetail(APIView):
        def get(self, request, pk):
            book = models.Book.objects.filter(pk=pk).first()
            ser = serializer.BookSerializer(instance=book)
            return Response(ser.data)
    
        def put(self, request, pk):
            book = models.Book.objects.filter(pk=pk).first()
            # 修改,instance和data都要传
            ser = serializer.BookSerializer(instance=book, data=request.data)
            if ser.is_valid():
                # 校验通过修改,不需要重写update
                ser.save()
                return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
            # 校验不通过
            return Response({'code:': 102, 'msg': '校验未通过,修改失败', 'error': ser.errors})
    
        def delete(self, request, pk):
            models.Book.objects.filter(pk=pk).delete()
            return Response({'code': 100, 'msg': '删除成功'})
    

    第一层五个接口demo#

    ModelSerializer序列化器实战 - HammerZe - 博客园 (cnblogs.com)

    第二层:基于GenericAPIView的五个接口

    常用类属性:#

    -GenericAPIView   继承了APIView,封装了一些属性和方法,跟数据库打交道
      	-queryset = None # 指定序列化集
        -serializer_class = None  # 指定序列化类
        -lookup_field = 'pk'  # 查询单条,分组分出来的参数,转换器对象参数的名字
        -filter_backends   # 过滤排序功能会用它
        -pagination_class  # 分页功能
        
        -get_queryset()  # 获取要序列化的数据,后期可能会重写
        -get_object()    # 通过lookup_field查询的
        -get_serializer()  # 使用它序列化
        -get_serializer_class() # 返回序列化类 ,后期可能重写
        
        
        
    demo:
    # 指定序列化集
    queryset = models.Book.objects.all()
    # 指定序列化类
    serializer_class = serializer.BookSerializer
    

    第二层五个接口demo#

    from rest_framework.response import Response
    
    
    from app01 import models
    from app01 import serializer
    from rest_framework.generics import GenericAPIView
    # 书视图类
    class BookView(GenericAPIView):
        # 指定序列化集
        queryset = models.Book.objects.all()
        # 指定序列化类
        serializer_class = serializer.BookSerializer
        def get(self, requets):
            # obj = self.queryset()
            obj = self.get_queryset() # 等同于上面
            # ser = self.get_serializer_class()(instance=obj,many=True)
            ser = self.get_serializer(instance=obj,many=True) # 等同于上面
            return Response(ser.data)
    
        def post(self, request):
            # 获取反序列化数据
            # ser = serializer.BookSerializer(data=request.data)
            ser = self.get_serializer(data = request.data)
            if ser.is_valid():
                # 校验通过存入数据库,不需要重写create方法了
                ser.save()
                return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
            # 校验失败
            return Response({'code': 101, 'msg': '校验未通过', 'error': ser.errors})
    
    
    class BookViewDetail(GenericAPIView):
        # 指定序列化集
        queryset = models.Book.objects.all()
        # 指定序列化类
        serializer_class = serializer.BookSerializer
        def get(self, request, pk):
            # book = models.Book.objects.filter(pk=pk).first()
            book = self.get_object() # 根据pk拿到单个对象
            # ser = serializer.BookSerializer(instance=book)
            ser = self.get_serializer(instance=book)
            return Response(ser.data)
    
        def put(self, request, pk):
            # book = models.Book.objects.filter(pk=pk).first()
            book = self.get_object()
            # 修改,instance和data都要传
            # ser = serializer.BookSerializer(instance=book, data=request.data)
            ser = self.get_serializer(instance=book,data=request.data)
            if ser.is_valid():
                # 校验通过修改,不需要重写update
                ser.save()
                return Response({'code:': 100, 'msg': '修改成功', 'data': ser.data})
            # 校验不通过
            return Response({'code:': 102, 'msg': '校验未通过,修改失败', 'error': ser.errors})
    
        def delete(self, request, pk):
            # models.Book.objects.filter(pk=pk).delete()
            self.get_object().delete()
            return Response({'code': 100, 'msg': '删除成功'})
    

    路由

    path('books/', views.BookView.as_view()),
    path('books/<int:pk>', views.BookViewDetail.as_view())
    

    总结:到第二层只需修改querysetserializer_class类属性即可,其余都不需要修改

    注意:虽然pk没有在orm语句中过滤使用,但是路由分组要用,所以不能删,或者写成*args **kwargs接收多余的参数,且路由转换器必须写成pk

    # 源码
    lookup_field = 'pk'
    lookup_url_kwarg = None
    

    get_queryset()方法可以重写,如果我们需要在一个视图类内操作另外表模型,来指定序列化的数据

    class BookViewDetail(GenericAPIView):
        queryset = models.Book.objects.all()
        ···
        '''
        指定序列化数据的格式:
        self.queryset()
        self.get_queryset() # 等同于上面
        queryset = models.Book.objects.all()
        '''
    	# 可以重写get_queryset方法在book视图类里操作作者模型
        def get_queryset(self,request):
            if self.request.path == '/user'
            return Author.objects.all()
        ···
        # 这样序列化的数据就不一样了,根据不同的条件序列化不同的数据
        
        '''当然还可以通过重写get_serializer_class来返回其他序列化器类'''
    

    第三层:基于GenericAPIView+五个视图扩展类写

    五个视图扩展类:from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin

    通过GenericAPIView+视图扩展类来使得代码更简单,一个接口对应一个扩展类,注意扩展类不是视图类

    • ListModelMixin:获取所有API,对应list()方法
    • CreateModelMixin:新增一条API,对应create()方法
    • UpdateModelMixin:修改一条API,对应update()方法
    • RetrieveModelMixin:获取一条API,对应retrieve()方法
    • DestroyModelMixin:删除一条API,对应destroy()方法

    注意:CreateModelMixin扩展类提供了更高级的方法,可以通过重写来校验数据存入

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

    第三层五个接口demo#

    from app01 import models
    from app01 import serializer
    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
    
    # 获取所有和新增API
    class BookView(ListModelMixin,CreateModelMixin,GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
        def get(self, request):
           return super().list(request)
    
        def post(self, request):
            return super().create(request)
    
    # 获取删除修改单个API
    class BookViewDetail(UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin,GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
        def get(self, request, *args,**kwargs):
            return super().retrieve(request, *args,**kwargs)
    
        def put(self, request, *args,**kwargs):
            return super().update(request, *args,**kwargs)
    
        def delete(self, request, *args,**kwargs):
            return super().destroy(request, *args,**kwargs)
    

    总结

    通过进一次封装+继承代码也变得越来越少了

    GenericAPIView速写五个接口demo#

    模型

    from django.db import models
    
    
    # Create your models here.
    
    # build four model tables
    
    class Book(models.Model):
        name = models.CharField(max_length=32)
        price = models.DecimalField(decimal_places=2, max_digits=5)
        publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
        def __str__(self):
            return self.name
    
        # 自定制字段
        @property
        def publish_detail(self):
            return {'name': self.publish.name, 'addr': self.publish.city}
    
    
        @property
        def author_list(self):
            l = []
            print(self.authors.all()) # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
    
            for author in self.authors.all():
                print(author.author_detail) # AuthorDetail object (1)
                l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
            return l
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
        @property
        def authordetail_info(self):
            return {'phone':self.author_detail.telephone,'addr':self.author_detail.addr}
    
    
    class AuthorDetail(models.Model):
        telephone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
    

    序列化器

    from django.db import models
    
    
    # Create your models here.
    
    # build four model tables
    
    class Book(models.Model):
        name = models.CharField(max_length=32)
        price = models.DecimalField(decimal_places=2, max_digits=5)
        publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
        authors = models.ManyToManyField(to='Author')
        def __str__(self):
            return self.name
    
        # 自定制字段
        @property
        def publish_detail(self):
            return {'name': self.publish.name, 'addr': self.publish.city}
    
    
        @property
        def author_list(self):
            l = []
            print(self.authors.all()) # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
    
            for author in self.authors.all():
                print(author.author_detail) # AuthorDetail object (1)
                l.append({'name': author.name, 'age': author.age, 'addr': author.author_detail.addr})
            return l
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
    
        def __str__(self):
            return self.name
    
        @property
        def authordetail_info(self):
            return {'phone':self.author_detail.telephone,'addr':self.author_detail.addr}
    
    
    class AuthorDetail(models.Model):
        telephone = models.BigIntegerField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
    

    视图

    from rest_framework.generics import GenericAPIView
    from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
        UpdateModelMixin
    
    from app01 import models
    from app01 import serializer
    
    
    # 书视图类
    class BookView(ListModelMixin, CreateModelMixin, GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
        def get(self, request):
            return super().list(request)
    
        def post(self, request):
            return super().create(request)
    
    
    class BookViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
        def get(self, request, *args, **kwargs):
            return super().retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return super().update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return super().destroy(request, *args, **kwargs)
    
    
    # 作者
    class AuthorView(ListModelMixin, CreateModelMixin, GenericAPIView):
        queryset = models.Author.objects.all()
        serializer_class = serializer.AuthorSerializer
    
        def get(self, request):
            return super().list(request)
    
        def post(self, request):
            return super().create(request)
    
    
    class AuthorViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
        queryset = models.Author.objects.all()
        serializer_class = serializer.AuthorSerializer
    
        def get(self, request, *args, **kwargs):
            return super().retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return super().update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return super().destroy(request, *args, **kwargs)
    
    
    # 作者详情
    
    class AuthorDetailView(ListModelMixin, CreateModelMixin, GenericAPIView):
        queryset = models.AuthorDetail.objects.all()
        serializer_class = serializer.AuthorDetailSerializer
    
        def get(self, request):
            return super().list(request)
    
        def post(self, request):
            return super().create(request)
    
    
    class OneAuthorViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
        queryset = models.AuthorDetail.objects.all()
        serializer_class = serializer.AuthorDetailSerializer
    
        def get(self, request, *args, **kwargs):
            return super().retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return super().update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return super().destroy(request, *args, **kwargs)
    
    
    # 出版社
    class PublishView(ListModelMixin, CreateModelMixin, GenericAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = serializer.PublishSerializer
    
        def get(self, request):
            return super().list(request)
    
        def post(self, request):
            return super().create(request)
    
    
    class PublishViewDetail(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView):
        queryset = models.Publish.objects.all()
        serializer_class = serializer.PublishSerializer
    
        def get(self, request, *args, **kwargs):
            return super().retrieve(request, *args, **kwargs)
    
        def put(self, request, *args, **kwargs):
            return super().update(request, *args, **kwargs)
    
        def delete(self, request, *args, **kwargs):
            return super().destroy(request, *args, **kwargs)
    
    

    路由

    from django.contrib import admin
    from django.urls import path
    
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        # 书
        path('books/', views.BookView.as_view()),
        path('books/<int:pk>', views.BookViewDetail.as_view()),
    
        # 作者
        path('authors/', views.AuthorView.as_view()),
        path('authors/<int:pk>', views.AuthorViewDetail.as_view()),
    
        # 作者详情
        path('authorsdetail/', views.AuthorDetailView.as_view()),
        path('authorsdetail/<int:pk>', views.OneAuthorViewDetail.as_view()),
    
        # 出版社
        path('publish/', views.PublishView.as_view()),
        path('publish/<int:pk>', views.PublishViewDetail.as_view()),
    ]
    
    

    Postman以及测完,请放心使用~

    第四层:GenericAPIView+九个视图子类写五个接口

    导入视图子类from rest_framework.generics import CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView

    使用哪个继承哪个就可以了,具体可以看继承的父类里有什么方法不需要刻意去记

    from rest_framework.generics import  CreateAPIView,ListAPIView,DestroyAPIView,RetrieveAPIView,UpdateAPIView,ListCreateAPIView,RetrieveUpdateAPIView,RetrieveUpdateDestroyAPIView,RetrieveDestroyAPIView
    
    # 1、查询所有,新增API
    class BookView(ListCreateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    # 2、新增接口
    class BookView(CreateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    # 3、查询接口
    class BookView(ListAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    # 4、查询单个,修改一个,删除一个接口
    class BookViewDetail(RetrieveUpdateDestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    # 5、查询单个接口
    class BookViewDetail(RetrieveAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    # 6、修改单个接口
    class BookViewDetail(UpdateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    # 7、删除单个接口
    class BookViewDetail(DestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    # 8、查询单个、修改接口
    class BookViewDetail(RetrieveUpdateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    
    # 9、查询单个、删除接口
    class BookViewDetail(RetrieveDestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    '''上述共九个视图子类,九九归一剑诀~'''
    
    # 更新和删除接口自己整合
    class BookViewDetail(UpdateAPIView,DestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    

    第四层快速写五个接口demo#

    from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
    
    from app01 import models
    from app01 import serializer
    
    class BookView(ListCreateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    
    class BookViewDetail(RetrieveUpdateDestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    '''其余的和第三层一样'''
    

    第五层:基于ViewSet写五个接口

    视图集导入from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin

    路由导入from rest_framework.routers import SimpleRouter,DefaultRouter

    基于ViewSet视图集写,需要我们配置路由

    • 方法一

      from django.urls import path, include
      from rest_framework.routers import SimpleRouter
      from app01 import views
      
      router = SimpleRouter()
      router.register('books', views.BookView, 'books')
      urlpatterns = [
          ...
      ]
      urlpatterns += router.urls
      '''
      register(self, prefix, viewset, basename=None)
      prefix:路由url前缀
      viewset:处理请求的viewset类
      basename:路由名称的前缀,一般和prefix写成一样就行
      '''
      # 等同于
      path('books/'),include(router.urls)
      path('books/<int:pk>'),include(router.urls)
      
    • 方法二

      router = SimpleRouter()
      router.register('books', views.BookView, 'books')
      
      urlpatterns = [
          ...
          url(r'^', include(router.urls))
      ]
      
      
      # 生成两种路由
      path('/api/v1'),include(router.urls)
      # [<URLPattern '^books/$' [name='books-list']>, <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>]
      # 等同于自己配的
      path('/api/v1/books/'),include(router.urls)
      path('/api/v1/books/<int:pk>'),include(router.urls)
      

      异同

      • 同:方法一和方法二都可以自动生成路由,代替了下面的路由

        path('books/', views.BookView.as_view()),
        path('books/<int:pk>', views.BookViewDetail.as_view()),
        
      • 异:方法二可以拼接路径,如果不拼接是和方法一一样的

    两种不同的路由

    image

    image

    第五层基于ModelViewSet视图集写五个接口demo#

    views.py

    from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
    class BookView(ModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    

    urls.py

    from django.contrib import admin
    from django.urls import path, include
    from rest_framework.routers import SimpleRouter
    
    from app01 import views
    
    router = SimpleRouter()
    router.register('books', views.BookView, 'books')
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/v1/',include(router.urls)),
    ]
    

    ps:剩下的都一样~

    ReadOnlyModelViewSet视图集#

    继承该ReadOnlyModelViewSet视图集的作用是只读,只做查询,修改删除等操作不允许

    from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet,ViewSet,GenericViewSet,ViewSetMixin
    class BookView(ReadOnlyModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = serializer.BookSerializer
    

    image

    两个视图集总结#

    • ModelViewSet可以写五个接口,而ReadOnlyModelViewSet只能写两个接口

    本质

    • ModelViewSet继承了五个视图扩展类+GenericViewSet,GenericViewSet继承了ViewSetMixin+GenericAPIView

      PS:ViewSetMixin控制了路由写法

    • ReadOnlyModelViewSet继承了RetrieveModelMixin+ListModelMixin+GenericViewSet

    其他视图集#

    ViewSet#

    ViewSet = ViewSetMixin+APIView

    
    class ViewSet(ViewSetMixin, views.APIView):
        """
        The base ViewSet class does not provide any actions by default.
        """
        pass
    

    GenericViewSet#

    GenericViewSet = ViewSetMixin+GenericAPIView

    class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
        """
        The GenericViewSet class does not provide any actions by default,
        but does include the base set of generic view behavior, such as
        the `get_object` and `get_queryset` methods.
        """
        pass
    

    ViewSetMixin#

    魔术视图类,控制自动生成路由,可以通过组合继承,以前的写法可以继续使用,但是如果要自动生成路由必须得继承ViewSetMixin及其子类;或者选择继承ViewSet、GenericViewSet

    class ViewSetMixin:
        """
        This is the magic.
    
        Overrides `.as_view()` so that it takes an `actions` keyword that performs
        the binding of HTTP methods to actions on the Resource.
    
        For example, to create a concrete view binding the 'GET' and 'POST' methods
        to the 'list' and 'create' actions...
    
        view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
        """
    这就是魔法。  
     
    重写' .as_view() ',以便它接受一个' actions '关键字执行  
    将HTTP方法绑定到资源上的动作。  
     
    例如,创建绑定'GET''POST'方法的具体视图  
    到“列表”和“创建”动作…  
     
    = MyViewSet视图。 As_view ({'get': 'list''post': 'create'})  
    

    总结

    • 第一层:基于APIView写视图,get、post、put、delete都需要自己写,序列化的数据和序列化类需要获取后指定

      class BookView(APIView):
          def get(self, requets):
              book_list = models.Book.objects.all()
              ser = serializer.BookSerializer(instance=book_list, many=True)
              return Response(ser.data)
      
    • 第二层:基于GenericAPIView写视图,优化了视图类内序列化数据和序列化类的代码冗余问题,通过querysetserializer_class指定序列化集和序列化器即可,一个视图类内写一次即可,最后通过get_querysetget_serializer方法处理

      class BookView(GenericAPIView):
          queryset = models.Book.objects.all()
          serializer_class = serializer.BookSerializer
          def get(self, requets):
              obj = self.get_queryset() 
              ser = self.get_serializer(instance=obj,many=True) 
              return Response(ser.data)
      
    • 第三层:基于GenericAPIView+5个视图扩展类写视图,每个扩展类对应一个接口,更加细化,通过继承父类(扩展类)减少了代码的冗余

      class BookView(ListModelMixin,CreateModelMixin,GenericAPIView):
          queryset = models.Book.objects.all()
          serializer_class = serializer.BookSerializer
          def get(self, request):
             return super().list(request)
      
    • 第四层,基于九个视图子类写,视图子类将扩展类和GenericAPIView封装到一块,使得我们要写的代码更少了,总之就是牛逼~

      class BookView(ListCreateAPIView):
          queryset = models.Book.objects.all()
          serializer_class = serializer.BookSerializer
      
    • 第五层,基于ViewSet写视图,这样以来5个接口就都在一个视图类内,代码更少了,但是可扩展性低了,路由也是问题,get所有和get一条路由冲突需要修改

      class BookView(ModelViewSet):
          queryset = models.Book.objects.all()
          serializer_class = serializer.BookSerializer
      '''路由'''
      router = SimpleRouter()
      router.register('books', views.BookView, 'books')
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          path('api/v1/',include(router.urls)),
      ]
      

    补充

    视图集中定义附加action动作#

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

    举例:

    from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
    class StudentModelViewSet(ModelViewSet):
        queryset = Student.objects.all()
        serializer_class = StudentModelSerializer
    
        def login(self,request):
            """学生登录功能"""
            return Response({"message":"登录成功"})
    

    url的定义

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

    action属性#

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

    例如:

    from rest_framework.viewsets import ModelViewSet
    from students.models import Student
    from .serializers import StudentModelSerializer
    from rest_framework.response import Response
    class StudentModelViewSet(ModelViewSet):
        queryset = Student.objects.all()
        serializer_class = StudentModelSerializer
    
        def get_new_5(self,request):
            """获取最近添加的5个学生信息"""
            # 操作数据库
            print(self.action) # 获取本次请求的视图方法名
            
            
    通过路由访问到当前方法中.可以看到本次的action就是请求的方法名
    


    累死🐵,有错误请指正~感谢
  • 相关阅读:
    您是否正确使用SOLIDWORKS Electrical 绘制电气原理图?
    分享会(一) - 使用IDEA系列软件debug的全面技巧(Python为例)
    (c语言)移位操作符
    H3C GRE over ipsec配置
    OpenAI的GPT-4.5 Turbo:意外曝光且可能在六月份推出
    pytorch实现卷积操作
    【云原生之kubernetes实战】在k8s环境下部署Teleport堡垒机系统
    vscode一键生成佛祖保佑永无bug
    Node.js 商标转让给 OpenJS 基金会
    【操作系统】聊聊CPU上下文切换实操
  • 原文地址:https://www.cnblogs.com/48xz/p/16089640.html