drf视图之两个视图基类、5个视图扩展类、9个视图子类以及视图集

两个视图基类

APIView

APIView是restframework提供的所有视图的基类,继承自django的view父类。

APIView与View的不同之处在于:

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

支持定义的类属性

  • authentication_classes:列表或元组,身份认证类
  • permission_classes:列表或元组,权限检查类
  • throttle_classes:列表或元组,流量控制类

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

GenericAPIView通用视图类

from rest_framework.generics import GenericAPIView

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

两个属性

  • queryset:指定要序列化的数据库查询的结果集

  • serializer_class:指名视图使用的序列化器

三个方法

get_queryset(self):

返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写。例如:

def get_queryset(self):
  user=self.request.user  # 获取当前user表对象
  return user.accounts.all() # 返回 user表扩表后的account表Queryset对象

get_serializer_class(self)或get_serializer(self,*args,**kwargs)

  • get_serializer_class(self):当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化类名就可以让视图方法执行不同的序列化器对象了。返回序列化类,默认返回serializer_class,可以重写,例如:

    def get_serializer_class(self):
        if self.request.user.is_staff:
            return FullAccountSerializer
        return BasicAccountSerializer
    
  • get_serializer(self,*args,**kwargs)

    返回序列化器对象,主要用来提供给mixin扩展类用,如果我们在视图中想要获取序列化器对象,也可以直接调用该方法

注意:该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view。这三个数据对象可以在定义序列化器时使用。

  • request:当前视图的请求对象
  • view:当前请求的类视图对象
  • format:当前请求期望返回的数据格式

get_object(self)

返回详情视图所需的模类型数据对象,主要是用来提供给Mixin扩展类使用

在视图中调用该方法获取详情信息的模型类对象。若详情访问的模型类对象不存在,则会返回404

该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

class BookAndDetail(Books,BookDetail):
  	queryset = Book.objects
  	serializer_class = BookSerializer  
    def put(self,request,pk):
          res = self.get_object()
          ser = self.get_serializer(instance=res, data=request.data)
          if ser.is_valid():
              ser.save()
              return Response({'code': 100, 'msg': '修改成功'}, status=201)
          else:
              return Response({'code':101,'msg':ser.errors})

image-20221001095656053

补充了解

filter_queryset: 跟过滤有关系
paginate_xxx: 跟分页有关

基于APIView写5个接口

基于GenericAPIView写5个接口

5个视图扩展类

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

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

ListModelMinxin

列表视图扩展类,提供list(request,*args,**kwargs)方法快速实现列表视图,返回200状态码

该Mixin的list方法会对数据进行过滤和分页

源码

image-20221001103721328

代码演示

from rest_framework.mixins import ListModelMixin
from app01 import models

class Books(ListModelMixin,GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    def get(self,request):
        return self.list(request)

CreateModelMixin

创建视图扩展类,提供create(request,*args,**kwargs)方法快速实现创建资源的视图,成功返回201状态,如果序列化器对前端发送的数据验证失败,返回400错误。

源代码

image-20221001105923270

RetrieveModelMinxin

详情视图扩展类,提供了retrieve(request,*args,**kwargs)方法,可以快速实现返回一个存在的数据对象。如果存在,返回200,否则返回404.

源码

image-20221001110841066

代码演示:

queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = 'id'
    def get(self,request,id):
        instance=self.get_object()
        return self.retrieve(request)

UpdateModelMixin

更新视图扩展类,提供update(reuqest,*args,**kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供了partial_update(reuqest,*args,**kwargs)方法,可以实现局部更新,成功返回200,序列化器校验数据失败时,返回400错误。

源代码

image-20221001111933865

DestoryModelMixin

删除视图扩展类,提供destory(reuqest,*args,**kwargs)方法,可以快速实现删除一个存在的数据对象。成功返回204,不存在返回404.

源代码:

image-20221001111954912

基于GenericAPIView+5个视图扩展类写接口

from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
from app01 import models

class Books(ListModelMixin,CreateModelMixin,GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

class BookDetail(RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = 'id'  # 源码中默认为pk,可以指定修改

9个视图子类

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

基于9个视图子类写接口

class Books(ListCreateAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer

class BookDetail(RetrieveUpdateDestroyAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = 'id'

视图集

视图集ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

list()     提供一组数据
retrieve() 提供单个数据
create()   创建数据
update()   保存数据
destory()  删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作action如list()create()等。视图集只能使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

# 视图
class Book(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = 'id'
    def login(self,request):
        return HttpResponse('登录')

# 一旦使用视图集中的类,就要这种写法:get请求对应的action是login方法,一旦发起get请求,就会执行对应的login方法
path('books/',views.Book.as_view({'get':'login','post':'create'})),  path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
image-20221001131222609

继承ModelViewSet编写5个接口

视图层

from rest_framework.viewsets import ModelViewSet
class Book(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = BookSerializer
    lookup_field = 'id'

一旦使用视图集中的类,就要去路由修改写法

path('books/',views.Book.as_view({'get':'list','post':'create'})),  path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'})),

常用视图集父类

ViewSet

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

ViewSet主要通过继承ViewSetMixin来实现调用as_view()时传入字典(如{'get':'list'})的映射工作,在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

GenericViewSet

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

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

class Book(GenericViewSet,ListCreateAPIView,RetrieveUpdateDestroyAPIView):
    queryset =models.Book.objects
    serializer_class = BookSerializer
    lookup_field = 'id'

path('books/',views.Book.as_view({'get':'list','post':'create'})),
    path('books/<int:id>/',views.Book.as_view({'get':'retrieve','put':'update','delete':'destroy'})),

ModelViewSet

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

ReadOnlyModelViewSet

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

源码分析ViewSetMixin

ViewSetMixin:是一个magic
一旦继承他之后:路由写法就变了,变成映射关系了,在视图类中可以写任意的方法名了

@classonlymethod
    def as_view(cls, actions=None, **initkwargs):
        # 路由中as_view中必须穿参数,必须传字典:{'get':'list','post':'create'}
        if not actions:
            raise TypeError("The `actions` argument must be provided when "
                            "calling `.as_view()` on a ViewSet. For example "
                            "`.as_view({'get': 'list'})`")
        # 路由匹配成功,执行view(request),request是老的request
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            # method:get	action:list
            # self 是视图类的对象中通过反射,查找list,
            # handler视图类中的list方法
            for method, action in actions.items():
                handler = getattr(self, action)
                # 向视图类的对象中,反射 method:get,handler:list方法
                # self.get=list
                setattr(self, method, handler)

            self.request = request
            self.args = args
            self.kwargs = kwargs
            return self.dispatch(request, *args, **kwargs)
        return csrf_exempt(view)

'只要继承了ViewSetMixin,以后路由写法变了,都要写成:views.Book.as_view({'get':'list','post':'create'})'
这样写好以后,对应的请求方法来了,就会执行配置的方法

扩展:以后只要继承了ViewSetMixin,视图类中可以写任意名字的方法,不用非得写get,post,delete

总结

APIView

as_view,dispatch

GenericAPIView

继承了APIView

两个类属性
三个方法

5个视图扩展类

RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestoryModelMixin,ListModelMixin
每个类里面有一个方法

9个视图子类

5个视图扩展类+GenericAPIView的组合

视图集

ViewSetMixin:魔法,重写了as_view,只要继承他,路由写法就变了
ViewSet:ViewSetMixin+APIView
GenericViewSet:ViewSetMixin+GenericAPIView
ModelViewSet:5个视图扩展类+GenericViewSet
ReadOnlyModelViewSet:两个视图扩展类+GenericViewSet
posted @ 2022-10-01 15:56  荀飞  阅读(129)  评论(0编辑  收藏  举报