drf-视图组件

一、视图

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

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

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

1.  两个视图基类

1.1 APIView

from rest_framework.views import APIView

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

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

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

复制代码
###### 第一层: 继承APIView编写book5个接口
from rest_framework.views import APIView
from rest_framework.response import Response
from .serializer import BookSerializer
from .models import Book


class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()  # 反序列化保存
            return Response(ser.data)  # 创建成功后,返回创建后的对象, 做了个序列化
        else:
            return Response(ser.errors)
复制代码
复制代码
class BookDetailView(APIView):
    def get(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

    def delete(self, request, pk):
        Book.objects.filter(pk=pk).delete()
        return Response('')
复制代码

1.2 GenericAPIView[通用视图类]

from rest_framework.generics import GenericAPIView

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

提供的关于数据库查询的属性与方法

写get_queryset的目的:后期通过重写

    • ### 重要属性:

      • queryset : 以后放所有某个表查询出的数据
      • Serializer_class : 要序列化的类
      • get_object  :修改,查询的单条
    • ### 重要方法###
      -get_queryset :要序列化的所有数据,qs对象
      -get_serializer :序列化类
      -get_object :修改,查询,删除 的单条

    • 了解类属性:

      • lookup_field = 'pk'  路由使用转换器,转换出来的参数,查询单条要用到,如果改了,路由对应也要修改,一般不改

      • filter_backends:后面详细讲     过滤 功能
      • pagination_class :后面详细讲  分页
         
    • 了解方法:

      • get_serializer_class  后期咱们可能会重写它,指定某些方法使用不同的序列化类

      • filter_queryset 后面跟过滤功能一起讲

代码:

复制代码
from rest_framework.generics import GenericAPIView

from .models import Publish
from .serializer import PublishSerializer
class PublishView(GenericAPIView):
    # 本次视图类中要操作的数据
    queryset = Publish.objects.all()  # 类只要加载,就会执行,查了所有数据,不能以它为准
    # 本次视图类中要调用的默认序列化器
    serializer_class = PublishSerializer

    def get(self, request):
        # 获取所有的出版社数据
        obj_list = self.get_queryset()  # 以用的时候为准
        # 使用对应的序列化类进行处理数据
        ser = self.get_serializer(instance=obj_list, many=True)
        return Response(ser.data)

    def post(self, request):
       # 使用对应的序列化类进行处理数据
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            ser.save()  # 反序列化保存
            return Response(ser.data)  # 创建成功后,返回创建后的对象, 做了个序列化
        else:
            return Response(ser.errors)


class PublishDetailView(GenericAPIView):
    serializer_class = PublishSerializer # 要给这两个参数传对应的值
    queryset = Publish.objects.all()
     
    def get(self, request, pk):
        # 查询对应PK的那条数据
        obj = self.get_object()
        ser = self.get_serializer(instance=obj)
        return Response(ser.data)

    def put(self, request, pk):
        obj = self.get_object()
        ser = self.get_serializer(instance=obj, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)

    def delete(self, request, pk):
        self.get_object().delete()
        return Response('')        
复制代码

对应的序列化类:

class PublishSerializer(serializers.ModelSerializer):
    class Meta:
        model=Publish
        fields='__all__'

总结:

  # 易犯的错误1:一定要在用数据的时候再查

    def get_queryset(self):

      return self.queryset.all()

  #  错误2:咱么没有在类属性上配置 queryset这个参数--->源码中做了断言

2. 5个视图扩展类

作用:

提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

RetrieveModelMixin, 查询一条,写了一个方法 retrieve---》代码就是 跟咱们之前写获取单条get方法内容一样

CreateModelMixin 新增一条写了一个方法 create---》代码就是 跟咱们之前写新增一条 post 方法内容一样

DestroyModelMixin,删除一条写了一个方法 destroy---》代码就是 跟咱们之前写删除一条 delete 方法内容一样

ListModelMixin,查询所有写了一个方法 list---》代码就是 跟咱们之前写删除一条 get 方法内容一样

UpdateModelMixin 修改一个写了一个方法 update---》代码就是 跟咱们之前写删除一条put 方法内容一样

为什么要写5个视图扩展类,不写俩?

  因为后期不一定 5个接口都写

代码:

复制代码
class PublishView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Publish.objects.all()  # 类只要加载,就会执行,查了所有数据,不能以它为准
    serializer_class = PublishSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):
        # return  self.create(request) # 一定不要忘了return
        return super().create(request)  # 一定不要忘了return


class PublishDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    serializer_class = PublishSerializer
    queryset = Publish.objects.all()

    def get(self, request, pk):
        return self.retrieve(request, pk)

    def put(self, request, pk):
        return self.update(request, pk)

    def delete(self, request, pk):
        return self.destroy(request, pk)
复制代码

 3. 9个视图子类

from rest_framework.generics import ListAPIView, CreateAPIView, ListCreateAPIView

 1. ListAPIView:提供get方法

  继承自:GenericAPIView、ListModelMixin

2. CreateAPIView:提供了post方法

  继承自:GenericAPIView、CreateModelMixin

3. ListCreateAPIView:提供了get、post方法

  继承自:GenericAPIView、ListModelMixin、CreateModelMixin

from rest_framework.generics import RetrieveAPIView, DestroyAPIView, UpdateAPIView

4.  RetrieveAPIView:提供了get方法

  继承自:GenericAPIView、RetrieveModelMixin

5. DestroyAPIView:提供了delete方法

  继承自:GenericAPIView、DestroyModelMixin

6. UpdateAPIView:提供了put方法

  继承自:GenericAPIView、UpdateModelMixin

from rest_framework.generics import RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView

7.RetrieveUpdateDestroyAPIView:提供了get、put、delete方法

  继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin

8. RetrieveDestroyAPIView:提供了get、delete方法

  继承自:GenericAPIView、RetrieveModelMixin、DestroyModelMixin

9.RetrieveUpdateAPIView:提供了get、put 方法

  继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin

以后想写5个接口中的某一个或某几个或所有,只需要选择继承不同的类即可,类中只需要配置两个类属性:queryset = XX.objectes.all()、serializer_class = XXSerializer

代码:

1. 利用九个视图子类来写接口

复制代码
#1利用九个视图子类来写  
#publish: 查询所有,查询单条,修改一条,新增一条,删除一条的接口
class PublishView(ListCreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializerclass PublishDetailView(RetrieveUpdateDestroyAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
#2 想写  publish: 查询单条,新增一条,的接口--->使用9个视图子类编写class PublishView(CreateAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializerclass PublishDetailView(RetrieveAPIView):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
复制代码

2. 利用五个视图扩展类来写接口

复制代码
#3 想写  publish: 查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def post(self,request,*args,**kwargs):
        return self.create(request,*args,**kwargs)
class PublishDetailView(GenericAPIView,RetrieveModelMixin):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer
    def get(self,request,*args,**kwargs):
        return self.retrieve(request,*args,**kwargs)
复制代码

3. 路由:

path('publish/', PublishView.as_view()),
path('publish/<int:pk>', PublishView.as_view()),

4. 视图集

1. ModelViewSet

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

只要视图类继承了ModelViewSet,路由写法就变了。改一下路由写法,五个接口都有了

代码:

from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
    queryset = Publish.objects.all()
    serializer_class = PublishSerializer

路由:

配置好请求方式和方法的对应关系
path('publish/', PublishView.as_view({'get':'list','post':'create'})),
path('publish/<int:pk>', PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),

1.1 ModelViewSet源码分析

 查询所有接口:get请求---》执行list,然后拿到所有的数据,序列化,再返回序列化的数据结果

 新增一条:-post---create---》之前咱们写的新增的代码一样的

 然后发现在ViewSetMixin类中,重写了as_view方法,在调用as_view()时传入字典(如{‘get’:’list’})的映射处理工作。

2. ViewSetMixin

ViewSetMixin决定了路由的写法,所以路由写法就变成了有对应关系,方法名可以随便写只要做好对应关系,如下:

path('publish/', PublishView.as_view({'get':'list','post':'create'}))
path('publish/', PublishView.as_view({'get':'lqz'})) # 做好对应关系

原来执行的是APIView中的as_view,现在继承了ViewSetMixin后,执行的就是ViewSetMixin的as_view

GenericViewSe源码分析:

-class GenericViewSet(ViewSetMixin, generics.GenericAPIView):ViewSetMixin必须放前面--》保证执行的as_view是ViewSetMixin的

 ViewSetMixin的源码分析:

 对actions参数进行一个判断,当路由中没有传actions时,就会抛出异常,而且必须以字典的形式传actions。

-请求来了,路由匹配成功---》执行ViewSetMixin的as_view内的view(request)

ViewSetMixin的as_view内的view(request)源码分析:

 # 总结:

  -路由中这样配置:PublishView.as_view({'get':'list','post':'create'})

  -以后get请求过来,本质执行的就是视图类中的list方法

只要继承的类是:ViewSetMixin ,就能视图类中方法任意命名,路由写法变化,以后视图类中方法名可以随意命名,只要路由做好映射

ReadOnlyModelViewSet:以后写的接口,只想有 获取单条和获取所有,继承它,只序列化

3. 视图类的总结

# 1 两个视图基类

-APIView和GenericAPIView
-APIView的执行流程:包装了新的 处理了csrfrequeset,执行了3大认证,处理全局异常
-GenericAPIView:要做序列化,要跟数据库打交道,就直接继承它即可

重要属性:
  -queryset:以后放所有某个表查询出的数据
  -serializer_class:要序列化的类
重要方法:
  -get_object:查询、修改、删除的单条数据
  -get_queryset:要序列化的所有的数据,qs对象
  -get_serializer:序列化类

#2. 5个视图扩展类(不是视图类),需要GenericAPIView才能用

-快速使用5个接口
-某几个接口:查询单条,新增一条,的接口--->使用5个视图扩展类+GenericAPIView
class PublishView(GenericAPIView,CreateModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def post(self,request)
return self.create(request)
class PublishDetailView(GenericAPIView,RetrieveModelMixin)
queryset=Publish.objects.all()
serializer_class=序列化类
def get(self,request)
return self.retrieve(request)

#3. 9个视图子类(继承GenericAPIView+5个视图扩展类的组合)

ListAPIView, CreateAPIView
ListCreateAPIView

RetrieveAPIView, DestroyAPIView, UpdateAPIView
RetrieveUpdateDestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView

# 4 视图集 -ModelViewSet:

-ViewSetMixin+GenericAPIView+5个视图扩展类
-GenericViewSet+5个视图扩展类

-ViewSetMixin源码:路由做映射的配置,以后视图类中方法可以随便命名
-Viewset:ViewSetMixin+APIView---》不需要要序列化,路由写法变了
-GenericViewSet:ViewSetMixin+GenericAPIView--》需要序列化,需要用数据库,路由写法变化
-ReadOnlyModelViewSet:list和retrieve

 

 

  

posted @   Maverick-Lucky  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示