django rest framework中对于APIView、GenericAPIView 、ModelViewSet 、mixins扩展类的分析 。

APIView

示例

根据实际程序来分析:

urls.py

urlpatterns = [
    re_path('users', UserAPIView.as_view())
]

views.py

class UserAPIView(APIView):
  
    def get(self, request):
        users = User.objects.filter().all()
        ser = UserSerializer(instance=users, many=True)
        return CommonResponse(status=status.HTTP_200_OK, data=ser.data)

源码分析

首先 ,

UserAPIView
继承了
APIView
,而
APIView
继承了
View
。

原生

View
里面定义了允许的http访问方式。

urls.py
中,
UserAPIView.as_view()
这条语句其实执行的是
APIView
中的
as_view()
方法,而
APIView
中的
as_view()
方法执行父类
View
as_view()
方法。

APIView中的as_view()

View中的as_view()

其中关键的方法为

dispatch
方法 ,根据
UserAPIView-->APIView-->View
的继承顺序,该方法执行的是
APIView
中的
dispatch
方法 。看下图。

dispatch
方法会获取请求方式,判断是否是http允许的请求方式 ,如果是的话,则分发执行
UserAPIView
中对应的同名方法。

其实我们也可以在

UserAPIView
中自定义
dispatch
方法,如下:

def dispatch(self, request, *args, **kwargs):
    func = getattr(self,request.method.lower())
    return func(request,*args,**kwargs)

总结:CBV基于反射实现根据请求方式不同 ,执行不同的方法 。

View与APIView的执行流程

View:

  1. as_view()
    是入口,得到view函数
  2. 请求来了调用
    view
    函数,内部调用
    dispatch
    函数完成请求分发
  3. dispatch
    函数将请求方式映射为视图类的同名方法 ,得到相应结果

APIView:

  1. as_view()
    是入口,通过执行父类中的
    as_view
    方法得到view函数,然后在返回
    view
    函数的时候免除csrf验证。
  2. 请求来了调用
    view
    函数 ,内部调用(APIView类中的)
    dispatch
    方法完成请求分发。
  3. dispatch
    方法中 ,将会二次封装request,完成三大验证(认证、授权、节流),再将请求方式映射为视图类的同名方法 ,完成请求的处理 。

GenericAPIView

执行流程

首先看看GenericAPIView的源码。

可以看出,

GenericAPIView
继承了
APIView
。然后还有几个比较重要的类属性,稍后用到再讲 。

再往下看它对外暴露的方法:

其实是比较少的 ,而且大多是

get_xxx
之类的方法,也就是说,它的
as_view()
、
dispatch
等方法 ,其实都是按照
APIView
的流程处理的。

重要方法

首先我们看

get_queryset()
,它的意思是批量查找数据库的数据:

  • 可以看到,queryset属性必须进行赋值 ,按照继承顺序,我们直接在自己定义的视图类中声明queryset属性并进行赋值。
  • 在if判断中,如果queryset是一个QuerySet对象 ,就获取全部 ,得到一个QuerySetDict对象,否则原样返回 。

QuerySetDict类型如下:

接下来看

get_object()
,它的意思是从数据库中获取单个对象:

  • filter_kwargs
    封装查找条件 ,
    get_object_or_404
    负责在queryset中查找符合条件的对象(object) 。
  • 看到这里就发现了,默认查询条件是用
    pk
    ,也就是说你的
    url
    中必须要用
    pk
    这个形参名进行分组捕获。否则就需要声明
    lookup_url_kwarg
     ,如果url中的参数为
    name
    ,那么
    lokup_url_kwarg="name"
    ,然后进行替换组建
    filter_kwargs
    。当然如果你的查询条件不是用的
    pk
     ,就需要修改
    lookup_field
    为字段名,如我不是按照
    pk
    进行查询,而是按照
    name
     ,就修改
    lookup_field
    name
    。
  • 同时也会检查用户是否有权限查看该对象。
    check_object_permissions

主要的就是以上两个,

get_serializer()
会调用
get_serializer_class
获取序列化类,返回序列化类的执行结果。

示例

class UserAPIView(GenericAPIView):
    queryset = User.objects
    serializer_class = UserSerializer

    def get(self, request):
        users = self.get_queryset()
        ser = self.get_serializer(instance=users, many=True)
        return CommonResponse(status=status.HTTP_200_OK, data=ser.data)

mixins扩展类

  • rest_framework.mixins
    中 ,有五个扩展类 ,分别是:
    • ListModelMixin
      :该类主要负责查询所有记录
    • RetrieveModelMixin
      :该类主要负责查询单条记录
    • CreateModelMixin
      :该类主要负责创建记录
    • UpdateModelMixin
      :该类主要负责对记录做更新操作
    • DestroyModelMixin
      :该类主要负责删除记录
  • 这五个类都继承于
    object
    ,是独立的子类 。
  • 针对
    GenericAPIView
    更高级的封装,配合
    GenericAPIView
    使用有奇效。
  • 会自动进行
    return Response()
    ,所以就不用我们再对返回对象进行包装了。
方法 描述
ListModelMixin list() 查询所有,并返回Response对象
RetrieveModelMixin retrieve() 查询单条,并返回Response对象
CreateModelMixin create() 创建记录 ,并返回Response对象
UpdateModelMixin update() 更新记录,并返回Response对象
DestroyModelMixin destroy() 删除记录,并返回Response对象

示例

class UserAPIView(GenericAPIView, ListModelMixin):
    queryset = User.objects
    serializer_class = UserSerializer

    def get(self, request):
        return CommonResponse(status=status.HTTP_200_OK, data=self.list(request).data)

ModelViewSet

如果继承所有的mixins类 ,则视图类就会写的非常冗长,可读性较差 。

同时,每次都要在视图中return ,那我们会考虑能不能简化这步操作。

首先导入

ModelViewSet

from rest_framework.viewsets import ModelViewSet

查看它的源码:

再看

GenericViewSet

再看

ViewSetMixin

注释的意思是说,它重写了

as_view()
方法,绑定了http方法与视图函数中的方法 ,这让它必须接收一个
actions
参数 ,
actions
参数设置为一个字典。

示例

urls.py

urlpatterns = [
    re_path('users', UserAPIView.as_view(actions={"get": 'list'}))
]

views.py

class UserAPIView(ModelViewSet):
    queryset = User.objects
    serializer_class = UserSerializer

generics扩展类

至于generics扩展类,提供了以下几个功能:

功能
CreateAPIView 创建记录
DestroyAPIView 删除记录
UpdateAPIView 更新单条记录
ListAPIView 查询所有记录
RetrieveAPIView 查询单条记录
ListCreateAPIView 创建以及查询所有记录
RetrieveUpdateAPIView 更新以及查询单条记录
RetrieveDestroyAPIView 删除以及查询单条记录
RetrieveUpdateDestroyAPIView 删除、更新、查询单条记录
他们的实现也很简单,以`RetrieveDestroyAPIView`类举例:

由此可见 ,

generics
中的扩展类都是结合了
mixins扩展类
GenericAPIView
,并且提供了标准的http方法同名方法,这些方法又都分别执行对应的
mixins扩展类
中的方法 。这和我们
mixins扩展类
部分中的
示例
大体一致。

示例

urls.py

urlpatterns = [
    re_path('users', UserAPIView.as_view(actions={"get": 'list'}))
]

Views.py

class UserAPIView(ViewSetMixin, ListAPIView):
    queryset = User.objects
    serializer_class = UserSerializer

注:UserAPIView的as_view方法要接收actions参数 ,而我们要使用的就是ViewSetMixin中重写的as_view方法,因此为了不和ListAPIView中的as_view产生冲突,继承时要把ViewSetMixin放在前面。

看完上面的内容 ,下面再看这张图片,希望可以帮助梳理本篇文章的内容:

文章来源于网络,如有侵权请联系站长QQ61910465删除
本文版权归qu快排seo www.sEoguRuBlog.com 所有,如有转发请注明来出,竞价开户托管,seo优化请联系QQ√61910465