上面的mixins、generics都是rest_framework里的模块,我们可以继承其中的某些类,达到代码量减少的效果,这里充分体现出了面向对象的继承

一、mixins模块

mixins  : from rest_framework import mixins #导入方式
          存放一些增删改查的一些类  
          CreateModelMixin,ListModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin

二、generics模块

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
generics: from rest_framework import generics # 导入方式
          首先mixins文件中就是一个一个类,写着某些方法,但是你想用于CBV,必须继承django的View,这里我们用rest_framework则需继承APIView,
          这个py文件里定义了许多类,但是有一个最基本的类GenericAPIView(views.APIView),里面其他的类都会继承这个类,因为这个类定义的一些
          方法是专门提供于mixins文件里的类的,再看其他generics模块里的其他类,你会发现那么类全是基于mixins模块和GenericAPIView之间的组
          合,那么你想用rest_framework提供给我们的简便方法,那么必须要继承GenericAPIView,和mixins模块里的类。

三、通过一个简单的例子,顺带写mixins,generics的用处

eg:写一个接口,获取到所有书籍的数据,这里我只写视图类里的代码
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin
from app import models
from write_serializers import BooksSerializers

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

    def get(self,request,*args,**kwargs):
        return self.list(request, *args, **kwargs)
好了,上面就是我们通过rest_framework提供的方法之一,完成了一个简单的接口,
来一个GET请求,便会执行这个视图类的get方法,最终返回了self.list方法的执行结果,那我们去看看list方法是怎么执行的,
那么我们顺着继承的基类去找list方法,基于深度查询,我们找完GenericAPIView继承的基类们,并没有找到,那么我们去ListModelMixin
这个类中找,这个类很简单,就写了一个list方法。

   rest_framework -- mixins&generics Python 第1张

先看list方法,里面有self.filter_queryset(),self.paginate_queryset(),self.get_serializer()等等方法,很明显视图类中
没有写这些方法,ListModelMixin这个类里也没有,那么肯定在GenericAPIView,所以我之前就说了,GenericAPIView类是为mixins模块里
类提供方法的,所以二者必须一起使用。
分析1: queryset = self.filter_queryset(self.get_queryset())
queryset = self.filter_queryset(self.get_queryset()) 这行代码整体意思应该能看得懂吧,filter_queryset这个方法的返回值赋值给queryset,而filter_queryset的参数是get_queryset 的返回值,那么我们先去看filter_queryset这方法的参数是什么,也就是get_queryset的返回值
  rest_framework -- mixins&generics Python 第2张
首先,断言self.queryset这个属性的布尔值必须是True的,不是的话便会抛异常,我们先看GenericAPIView类中有没有这个属性(这并不是 属性的查找顺序),我们可以找到queryset = None,这样的话,我们再写视图类的话(前提是继承了这个类),没有写queryset这个属性或者值 为False,那么便会出错,所以queryset这个属性必须在视图类中为True。 根据这个我想到一点分享下,你可以用断言这种方法,指定它的子类必须要有该属性且值为True,对吧,方法也是一样,定义一个方法,在该方法 内写一个raise异常,rest_framework里很多就是通过这种方法,比如rest_framework.throttling.BaseThrottle这个类里的方法为allow_request。
接着上面继续,能走到return,就代表self.queryset肯定为True吧,前面的逻辑处理就不多说了。从现在看的话,那么这个queryset可以为 任何值吧,参数的值是什么了,继续看self.filter_queryset()这个方法的返回值
  rest_framework -- mixins&generics Python 第3张
这个你可以看它的注释,大概意思是将传来的参数queryset,再过滤一遍,self.filter_backends它的值为None,前提不进行任何设置,而 这个设置是在settings文件里的REST_FRAMEWORK,也就是之前进行全局设置登陆认证,权限认证的地方。不进行设置的话,还是会返回之前的 传进来的参数。最终赋值给queryset
分析2:page = self.paginate_queryset(queryset)
page = self.paginate_queryset(queryset) 参数我们知道是什么,直接看paginate_queryset方法吧
rest_framework -- mixins&generics Python 第4张
rest_framework -- mixins&generics Python 第5张
self.paginator它是被装饰成属性的方法,self.paginator它的返回不是None就是一个对象(这个对象是进行分页的),上面我们列举的例子 视图类中并没有写pagination_class这个属性,那么就会去找到默认pagination_class,默认值为None,如果你再视图类中写了该属性, 值应该是是一个类,最后会返回这个类的对象回去。如果self.paginator为True,那么self.paginator就是一个对象了,就会执行该对象 下面的paginate_queryset这个方法。 提醒:不管self.paginator这个对象是自定义的类产生的,还是rest_framework自带的,那么肯定会有paginate_queryset方法。它的返 回值肯定是某一页的对象列表。
分析3:serializer = self.get_serializer(queryset, many=True)
不管有没有进行分页,都会执行get_serializer这个方法,返回值为serializer,最终返回serializer.data
不难可以看出,我们写的视图类中必须要有serializer_class属性,且有值,这个和前面queryset这属性是一样的。最终返回序列化的对象
rest_framework -- mixins&generics Python 第6张
  
总结下:我们写的视图类必须要有serializer_class --->> 写序列化类
                                        queryset  ---->> queryset的对象
             可有可无看需求:pagination_class ---->>   进行分页的类
在GenericAPIView还有一个方法再说下get_object方法,这个方法在RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin都用上了,看方法名就差不多知道,返回一个对象。 rest_framework -- mixins&generics Python 第7张
 分析1: queryset = self.filter_queryset(self.get_queryset()) 这个跟之前分析的一样,(见上面的分析1) 分析2: lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field 这个其实没啥好说的,就说一点or,and的用法,我博客也写了这个,可以去看看 分析3: lookup_url_kwarg in self.kwargs 这句话很简单,判断lookup_url_kwarg这个值在不在self.kwargs这个容器里,但是这个self.kwargs到底是什么呢?self就是 当前的视图类的对象,它有kwargs这个属性? 先自己思考下,我在后面再写出来 分析4: obj = get_object_or_404(queryset, **filter_kwargs) 首先我们要弄清传的参数的是什么,filter_kwargs是一个字典({'pk':1}),那么**filter_kwargs就是pk=1,queryset这个就不 用在介绍了,看看这个方法get_object_or_404,
rest_framework -- mixins&generics Python 第8张
 rest_framework -- mixins&generics Python 第9张
 利用get方法,如果get里的参数不能找到唯一的一条数据的话,便会抛异常,通过捕捉异常去处理。程序顺利进行的话,那么返回的就是get 到的对象。 注意:属性的查看顺序,不要直接ctrl+鼠标左键,上面这个方法我就是直接ctrl+左键点进去的,虽然最后还是执行的这个方法,但是这是 误打误撞,在generics这个模块里,就有get_object_or_404方法。所以先去generics这个模块里get_object_or_404,再去 上面的get_object_or_404方法。。。 分析5: self.check_object_permissions(self.request, obj) 上面这行代码其实很熟悉,这个和之前进行用户权限认证差不多一样,不一样的是对谁进行权限认证,一个是用户,一个是一条记录(数据 库),也就是这里的obj。 rest_framework -- mixins&generics Python 第10张
 permission就是一个进行权限认证的对象,那么该对象必须要有has_object_permission方法,进行一系列判断,权限许可的话, 就返回True,不许可的话,返回False。光这么说,也不知道用在哪个地方,我想了个例子:首先obj就是我们从数据库拿到的数据 (对象),其实数据也分等级,也有不同权限的数据,我们可以再根据判断,再进行数据的返回。 提醒:这里我们是继承了GenericAPIView,它里面的get_object里做的权限认证,我们不继承GenericAPIView,也一样可以去 调用这个方法。但check_object_permissions方法是rest_framework提供的。 对于get_object方法的分析差不多了,再讲上面的分析3,self.kwargs哪里来的。 我们回到APIView中的dispatch方法就知道了
 generics这个模块里还有其他类,可以去看看,很简单就是类的继承问题。
好了,这块就写到这里了
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄