django rest framework之七:mixins模块及其GenericAPIView类源码分析

简单使用

 

url配置如下:

url(r"books/$",views.BookView.as_view()), 
url(r"bookdetail/(P<pk>\d+)/$",views.BookViewDetail.as_view()),

 

model类解析,用来校验请求参数的

class BookSerializers(serializers.ModelSerializer): 
    class Meta: 
        model=Book 
        fields="__all__"

 

视图类 

BookView是对book表的所有记录查询、增加某些数据记录 

BookViewDetail是对book表单条数据的查询、修改、删除

from rest_framework import mixins from rest_framework import generics

class BookView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView): 
    queryset = Book.objects.all() 
    serializer_class = BookSerializers 

    def get(self, request, *args, **kwargs): 
        return self.list(request, *args, **kwargs) 【数据集合查看】 

    def post(self, request, *args, **kwargs): 
        return self.create(request, *args, **kwargs) 【添加数据】

-------------------

BookView类多重继承了

mixins.ListModelMixin、 【数据集合查看】

mixins.CreateModelMixin、 【添加数据】

generics.GenericAPIView,

用来进行验证request请求,从而对book表的数据集合的查看、添加数据操作

-------------------

class BookViewDetail( mixins.RetrieveModelMixin, mixins.DestroyModelMixin, 
                        mixins.UpdateModelMixin, generics.GenericAPIView ): 
    queryset = Book.objects.all() 
    serializer_class = BookSerializers 
    
    def get(self,request, *args, **kwargs): 
        return self.retrieve(request, *args, **kwargs) 【单条数据查看】 

    def delete(self,request, *args, **kwargs): 
        return self.destroy(request, *args, **kwargs) 【删除】 

    def put(self,request, *args, **kwargs): 
        return self.update(request, *args, **kwargs) 【修改】

--------------------

BookViewDetail类,多重继承了

mixins.RetrieveModelMixin、 【单条数据查看】

mixins.DestroyModelMixin、 【删除】

mixins.UpdateModelMixin,、 【修改】

generics.GenericAPIView 

用来进行验证request请求,从而对book表进行单条数据查看、修改、删除操作

---------------------

 

=======================================================

 

我们先看mixins模块,该模块有如下几个类

class CreateModelMixin(object):增加

class ListModelMixin(object):展示数据列表

class RetrieveModelMixin(object):展示单条数据

class UpdateModelMixin(object):更新单条数据

class DestroyModelMixin(object):删除单条数据

 

在分析源码前,我们先来了解多重继承的一个知识点

class A: 
    def a(self): 
        print("A") 
        self.b() 

class B: 
    def b(self): 
        print("B") 

class D(A,B): 
    pass 

d = D() 
d.a()

 

会输出AB 

类D多重继承AB,类D实例对象d.a()时候,如果在类A中找不到b()方法,

它就会在多重继承的AB类中,横向寻找b方法,结果在类B中找到,然后输出

 

====================================================

 

GenericAPIView类

APIView源码分析,分析了APIView的大概执行流程,我们先看下多重继承类中的generics.GenericAPIView,看看它跟APIView有何关联?点开源码,原来GenericAPIView类是APIView的子类,继而扩充了一些其他的方法,我举出如下几个方法

 

【get_queryset】: 提供方法,用来【获取request请求封装完毕的结果集】

【get_object】: 【获取单条数据】

【get_serialize】: 【获取序列化后的数据】

【get_serializer_class】: 【获取需要序列化的model类】

【get_serializer_context】: 【获取序列化的数据,定义了某种格式的字典】

【paginator】: 【分页器】

 

在BookView中依然按着APIView的执行流程,通过请求方式,诸如get\post等,当request发起请求时,调用dispatch然后执行某个get\post,我们自己定义好的入口类方法,

 

===========================================

 

ListModelMixin分析

 

我们就以http://127.0.0.1:8000/books/(get方法)来举例,会执行如下代码:

def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)

 

该方法直接返回了self.list(request, *args, **kwargs), 

它会理所应当的去多重继承的父类中,去找寻方法,然后执行,跟踪代码会进入到ListModelMixin类

class ListModelMixin(object):
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

 

ListModelMixin类list方法是获取了queryset = self.filter_queryset(self.get_queryset()),这个queryset是在GenericAPIView类中,

queryset = Book.objects.all() 代码中定义

我前面列举了一些该类的方法, 

然后在判断是否分页,最后获取self.get_serializer(queryset, many=True)序列化类,最后将序列化后的结果serializer.data作为返回return Response(serializer.data)返回即可

 

以上就是http://127.0.0.1:8000/books/(get方法)查询所有的记录

 

=============================================

 

CreateModelMixin分析

 

对应BookView里面的post方法代码如下,流程大同小异 

http://127.0.0.1:8000/books/(post方法)添加记录

def post(self, request, *args, **kwargs):
    return self.create(request, *args, **kwargs)

 

跟进如下代码:

class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

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

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}

 

依然是从GenericAPIView多重继承类中获取序列化器,然后进行校验request请求的json数据或者form数据,然后进行serializer.save() 

用户Token验证,并且通过return {'Location': str(data[api_settings.URL_FIELD_NAME])}保存一个临时头部数据,最后 

将序列化的数据,响应状态码(201 Created:请求已经被实现)、头部一并返回即可

return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

 

以上就是http://127.0.0.1:8000/books/(post方法)添加操作

 

=================================================

 

RetrieveModelMixin分析

 

接下来简单看下单条数据的获取、更新、删除,先把视图代码贴出来

class BookViewDetail(
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    mixins.UpdateModelMixin,
    generics.GenericAPIView
):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self,request, *args, **kwargs):
        ret = self.get_object()
        print("ret~~~~~~~~~", ret)
        return self.retrieve(request, *args, **kwargs)

    def delete(self,request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def put(self,request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

 

 

执行流程也是大同小异 

获取单条数据时候,http://127.0.0.1:8000/bookdetail/7(get请求) 

执行get方法也是从GenericAPIView多重继承类中获取get_object,然后进行序列化,最后 return Response(serializer.data)返回即可

class RetrieveModelMixin(object):
    """
    Retrieve a model instance.
    """
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

 

============

 

UpdateModelMixin分析

 

接下来看下更新操作http://127.0.0.1:8000/bookdetail/7(put请求)

 

def put(self,request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class UpdateModelMixin(object):
    """
    Update a model instance.
    """
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response(serializer.data)

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

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)

 

意思通过instance = self.get_object()获取要修改的数据,然后get_serializer拿到序列化器、进行请求数据合法校验、然后通过Token进行用户验证、然后将更新好的数据返回return Response(serializer.data)

 

===============

 

DestroyModelMixin分析

 

接下来看下删除操作http://127.0.0.1:8000/bookdetail/7(delete删除请求)

def delete(self,request, *args, **kwargs):
    return self.destroy(request, *args, **kwargs)

class DestroyModelMixin(object):
    """
    Destroy a model instance.
    """
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def perform_destroy(self, instance):
        instance.delete()

 

通过pk(或者其他标识)获取要删除的数据,然后instance.delete()删除,最后返回return Response(status=status.HTTP_204_NO_CONTENT) 

HTTP 204(no content)表示响应执行成功,但没有数据返回,浏览器不用刷新

以上就是mixins模块源码分析

 

==================================================================

=====================================================================

 

利用generics

 

我们还可以利用如下更简单的方式

from rest_framework import generics

class BookView(generics.ListCreateAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

class BookViewDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializers

 

我们就看BookView即可原来继承如下的类,进行了再次的封装,代码更精简

 

BookView 继承自 generics.ListCreateAPIView ,而 ListCreateAPIView 源码如下:

也是继承自 (mixins.ListModelMixin,mixins.CreateModelMixin,

GenericAPIView) , 与我们自己之前写的 BookView 一样。

class BookView(mixins.ListModelMixin,
               mixins.CreateModelMixin,
               generics.GenericAPIView):

    queryset = Book.objects.all()
    serializer_class = BookSerializers

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)		【数据集合查看】

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)	【添加数据】

class ListCreateAPIView(mixins.ListModelMixin,
                        mixins.CreateModelMixin,
                        GenericAPIView):
    """
    Concrete view for listing a queryset or creating a model instance.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

 

========================================================

 

总结 :

我的接口一般继承 generics 模块里面的以下这些类就行了,如果对

get 、post 等方法有特殊的要求可以自己继承后重写 get、post 方法。

 

generics 模块里面有 :

GenericAPIView : 不提供 get 、 post 等方法,

要跟 mixins 中的模块一起继承才能使用 get 、 post 等方法

 

CreateAPIView : 提供 post 方法,用来【创建数据】。

继承自 mixins.CreateModelMixin 和 GenericAPIView

 

ListAPIView : 提供 get 方法,用来【获取数据集合】。

继承自 mixins.ListModelMixin 和 GenericAPIView

 

RetrieveAPIView : 提供 get 方法,用来【获取单条数据】。

继承自 mixins.RetrieveModelMixin 和 GenericAPIView

 

DestroyAPIView : 提供 delete 方法,用来【删除单条数据】

继承自 mixins.DestroyModelMixin 和 GenericAPIView

 

UpdateAPIView : 提供 put 和 patch 方法, 用来【修改单条数据】

继承自 mixins.UpdateModelMixin 和 GenericAPIView

 

ListCreateAPIView :

提供 get 和 post 方法,用来【获取数据集合】 和 【创建数据】

继承自 mixins.ListModelMixin,mixins.CreateModelMixin,和GenericAPIView

 

RetrieveUpdateAPIView :

提供 get 、 put 和 patch 方法,用来【获取】和【修改】单条数据

继承自 mixins.RetrieveModelMixin,mixins.UpdateModelMixin,和GenericAPIView

 

RetrieveDestroyAPIView :

提供 get 和 delete 方法,用来【获取】和【删除】单条数据

继承自 mixins.RetrieveModelMixin,mixins.DestroyModelMixin,和GenericAPIView

 

RetrieveUpdateDestroyAPIView :

提供 get 、 put、 patch 和 delete 方法,用来【获取】、【修改】和【删除】单条数据

继承自 mixins.RetrieveModelMixin,mixins.UpdateModelMixin,

mixins.DestroyModelMixin,和GenericAPIView

 

 

--------------------------------------------------------------------------------------

 

继承自 viewsets 里面的类的接口才能进行注册!!!

继承自 generics 里面的类的接口需要在路由里面调用 as_view()

可以给 get 和 post 传参数 :

url(r'^yy_staffs/$', UserList.as_view(), {'user_type': 1}),

 

class UserList(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):

def get(self, request, user_type, *args, **kwargs):

print(user_type)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值