drf之过滤排序源码、全局异常源码、认证,权限,频率源码分析、基于APIView编写分页

发布时间 2024-01-02 18:54:41作者: jntmwl

过滤排序源码

# 视图类中配置:filter_backends = [OrderingFilter]
# 1 入口---》查询所有---》ListModelMixin---》list---》完成了过滤
# 2 ListModelMixin---》list的方法--》必须配合继承GenericAPIView
	class ListModelMixin:
    def list(self, request, *args, **kwargs):
        # self.get_queryset() 所有数据---》all()
        # self.filter_queryset 完成了过滤和排序
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        return Response(data=serializer.data)
    
    
# 3 self.filter_queryset(总数据qs对象) ---》视图类的对象---》找到了GenericAPIView
    def filter_queryset(self, queryset):
        # 配置的一个个过滤类
        for backend in list(self.filter_backends):
            # 过滤类()---得到对象---》调用了对象的filter_queryset方法
            # self.request:request
            # queryset:qs总数据
            # self:视图类的对象
            # queryset 过滤后的数据
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset #经过你配置的过滤类排序类都操作完了--》返回qs对象
    
    
# 4 内置的具体如何排序的--》OrderingFilter--》一定重写了filter_queryset方法--》完成的排序
  def filter_queryset(self, request, queryset, view):
        # 通过视图类中配置的排序字段:view+前端传入的条件:request
        # ordering=price,id
        ordering = self.get_ordering(request, queryset, view)
        # [price,id]
        if ordering:
            return queryset.order_by(*ordering)
        return queryset
    
    
# 5 内置过滤如何实现---》SearchFilter--》一定重写了filter_queryset方法--》完成了过滤
    def filter_queryset(self, request, queryset, view):
        # 拿到查询字段:配置视图类中得
        search_fields = self.get_search_fields(view, request)
        # 拿到前端传入的查询字段
        search_terms = self.get_search_terms(request)
		# 都没有,就没过滤
        if not search_fields or not search_terms:
            return queryset

        orm_lookups = [
            self.construct_search(str(search_field))
            for search_field in search_fields
        ]

        base = queryset
        conditions = []
        for search_term in search_terms:
            queries = [
                models.Q(**{orm_lookup: search_term})
                for orm_lookup in orm_lookups
            ]
            conditions.append(reduce(operator.or_, queries))
        # 根据search的字段和传入的参数,拼接成or的查询条件,进行查询,返回结果
        queryset = queryset.filter(reduce(operator.and_, conditions))
        return queryset

全局异常源码

# 1 只要写了函数,配置在配置文件中,以后 视图类的方法或三大认证,只要除了异常都会调用咱们配置的函数

# 2 APIView中 dispatch中 有个try ,肯定在except 中执行的
APIView---dispatch---》
try:
    # 三大认证
    self.initial(request, *args, **kwargs)
	# 视图类的方能股份
    if request.method.lower() in self.http_method_names:
        handler = getattr(self, request.method.lower(),
                          self.http_method_not_allowed)
    else:
        handler = self.http_method_not_allowed
        response = handler(request, *args, **kwargs)

    except Exception as exc:
        # 就是这里,exc 异常对象
        response = self.handle_exception(exc)
        
        
# 3 self.handle_exception(exc)--->视图类的对象---》APIView中找
    def handle_exception(self, exc):
        #### 开始:如果没有认证通过,http响应状态码编程 403,向响应头放了点东西#### 
        if isinstance(exc, (exceptions.NotAuthenticated,exceptions.AuthenticationFailed)):
            auth_header = self.get_authenticate_header(self.request)
            if auth_header:
                exc.auth_header = auth_header
            else:
                exc.status_code = status.HTTP_403_FORBIDDEN
	   #### 结束#### 
       #exception_handler:就是我们写的那个 处理函数
        exception_handler = self.get_exception_handler()
	   # 上下文
        context = self.get_exception_handler_context()
        # exception_handler 咱们写的异常处理函数,接收两个参数
        # 第一个是错误对象
        # 第二个是:上下文--》对象--》里面有当次请求的requet,view
        response = exception_handler(exc, context)
		# 如果咱们写的 异常处理函数返回了None,它就不管了,直接抛给前端
        if response is None:
            self.raise_uncaught_exception(exc)
        return response
    
# 4 self.get_exception_handler() 如果拿到咱么写的异常处理函数的 APIView
	def get_exception_handler(self):
        """
        我们配置文件配置了,这个就会返回它
        REST_FRAMEWORK = {
            'EXCEPTION_HANDLER': 'app01.exceptions.common_exception_handler',
        }
        我们如果没配,就是默认的
        'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
        """
        # 你在配置文件中配置的
        return self.settings.EXCEPTION_HANDLER
    
# 5 读 EXCEPTION_HANDLER': 'rest_framework.views.exception_handler
def exception_handler(exc, context):
    if isinstance(exc, Http404):
        exc = exceptions.NotFound()
    elif isinstance(exc, PermissionDenied):
        exc = exceptions.PermissionDenied()
	# drf所有的异常,都继承了APIException,drf所有异常,都会走到这里
    if isinstance(exc, exceptions.APIException):
        if isinstance(exc.detail, (list, dict)):
            data = exc.detail
        else:
            data = {'detail': exc.detail}
	   # {detail:'认证失败'}
       # Response(data={'detail': exc.detail})
       # Response(data=字典或列表)
        return Response(data, status=exc.status_code, headers=headers)
	# 除了drf的异常,都没管,直接抛给前端
    return None


# 6 自己写
	drf已经处理了,统一返回格式,稍微做个处理

认证,权限,频率源码分析(了解)

1权限的源码执行流程

	-写一个权限类,局部使用,配置在视图类的,就会执行权限类的has_permission方法,完成权限校验

之前我们在学习drf的apiview的源码中,了解到在执行视图类方法之前执行了三大认证,同时两者都是处于dispatch异常捕获结构中的(需要注意这里的dispatch是APIView的方法,不是view中的dispatch方法)。

    -APIView类的497行左右, self.initial(request, *args, **kwargs)---》执行3大认证
    
# APIView类的399行左右:
    def initial(self, request, *args, **kwargs):
        # 能够解析的编码,版本控制(知道有这作用就好了,不用管,重点是下面部分)
        self.format_kwarg = self.get_format_suffix(**kwargs)
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

     	# 认证组件的执行位置
        self.perform_authentication(request)
        # 权限组件  [读它]
        self.check_permissions(request)
        # 频率组件
        self.check_throttles(request)

接着我们点进权限组件的执行源码查看

# APIView的326 左右
    def check_permissions(self, request):
        # self.get_permissions()----》[CommonPermission(),]
        # permission 是我们配置在视图类上权限类的对象
        for permission in self.get_permissions():
            # 权限类的对象,执行has_permission,这就是为什么我们写的权限类要重写has_permission方法	
            # self 是视图类的对象,就是咱们自己的的权限类的has_permission的view参数(具体的解释看下面)
            if not permission.has_permission(request, self):
                # has_permission方法的返回值是True或是False,如果return 的是False,就会走这里,走这里的结果是没有权限的情况
                # 如果配了多个权限类,第一个没过,直接不会再执行下一个权限类了
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
'在check_permissions中主要是一个for循环,而for循环的对象是get_permissions方法得到的结果,因此我们进来看看他是起了啥作用'
                
# APIView的274行左右  get_permissions
    def get_permissions(self):
        # self.permission_classes  是咱们配置在视图类上的列表,里面是一个个的权限类,没加括号就是没调用,他这里就相当于把这些权限类都加括号执行,把最后获取到的对象放到列表中返回出来
        # permission_classes = [CommonPermission]
        # [CommonPermission(),]   本质返回了权限类的对象,放到列表中
        return [permission() for permission in self.permission_classes]
    
'分析完之后回到上面'
    
    
'我们编写的权限类'
# 写权限类,写一个类,继承基类BasePermission,重写has_permission方法,在方法中实现权限认证,如果有权限return True ,如果没有权限,返回False
from rest_framework.permissions import BasePermission


class CommonPermission(BasePermission):
    def has_permission(self, request, view):
        # 实现权限的控制  ---》知道当前登录用户是谁?当前登录用户是  request.user
        if request.user.user_type == 1:
            return True
        else:
            # 没有权限,向对象中放一个属性 message
            # 如果表模型中,使用了choice,就可以通过  get_字段名_display()  拿到choice对应的中文
            self.message = '您是【%s】,您没有权限' % request.user.get_user_type_display()
            return False
    
'我们在这里重新定义了has_permission方法,在上面的源码中调用了这个方法,但是他的参数中,第二个参数是self,从我们定义的参数来看,我们可以知道这个self绑定给了view'
    
'看完之后还是回到上面'

总结:

  • APIView中的dispatch方法,dispatch方法内部执行了initial方法进行认证权限频率这三大认证,initial方法的倒数第二行执行了权限校验---》self.check_permissions(request)
  • 里面取出配置在视图类上的权限类,实例化得到对象,一个个执行对象的has_permission方法,如果返回False,就直接结束,不再继续往下执行,权限就认证通过
  • 如果视图类上不配置权限类:permission_classes = [CommonPermission],会使用配置文件的api_settings.DEFAULT_PERMISSION_CLASSES
    使用顺序是优先使用视图类中的局部配置,再优先使用项目配置文件中的配置,其次使用drf内置配置文件中的配置

2.认证源码分析

前面部分跟权限类的分析流程一样,不做详细解释了,到执行initial方法处为止。

# 之前读过:drf的apiview,在执行视图类的方法之前,执行了3大认证----》dispatch方法中的
    -497行左右, self.initial(request, *args, **kwargs)---》执行3大认证
    
# APIView类的399行左右:
    def initial(self, request, *args, **kwargs):
        # 能够解析的编码,版本控制(知道有这作用就好了,不用管,重点是下面部分)
        self.format_kwarg = self.get_format_suffix(**kwargs)
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

     	# 认证组件的执行位置【读它】
        self.perform_authentication(request)
        # 权限组件 
        self.check_permissions(request)
        # 频率组件
        self.check_throttles(request)
        
'我们进入认证组件的源码进行分析'
 # APIView的316行左右
    def perform_authentication(self, request):
        request.user #咱们觉得它是个属性,其实它是个方法,包装成了数据属性
        
        
 # Request类的user方法(用了APIView或是GenericAPIView后,在dispatch中重新定义了request,用Request产生的对象包装了一些,可以看第三天的博客)   Request的源码的219行左右
    @property
    def user(self):
        if not hasattr(self, '_user'):
            '咋们先看这里没有找到_user属性时执行的代码,可以看到执行了_authenticate方法,而当前的对象是Request类产生的,因此我们要去Request类中查找这个方法'
            with wrap_attributeerrors():
                self._authenticate()
        return self._user
    
    
 # self 是Request的对象,找Request类的self._authenticate()   373 行
    def _authenticate(self):
        # self.authenticators 跟我们在权限类的源码分析中见到的形式不一样,但是我们可以猜测两者的作用应该是相似的,就是我们配置在视图类上认证类的一个个对象,放到列表中
        # 点进源码我们发现他是在Request类初始化的时候,传入的(看下面)
        for authenticator in self.authenticators:
            try:
                # 而异常捕获内的代码也跟之前一样,是用于获取认证类中的重写的方法的结果返回了两个值。
                # 他有两种返回结果,第一种结果时返回两个值,第一个值是当前登录用户,第二个的token,只走这一个认证类,后面的不再走了
                # 第二种结果是可以返回None,会继续执行下一个认证类
                # 同时我们也可以看到,如果报错了就会直接停止运行,有返回值的时候会把值获取,然后返回出去
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                # 解压赋值(当我们在获取到认证类校验之后的结果后,会到下方的代码这里进行解压赋值):
                #self.user=当前登录用户,self是当次请求的新的Request的对象
                #self.auth=token
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()
        
        
        
 # self.authenticators  去Request类的init中找     152行左右
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        .....
        self.authenticators = authenticators or ()
		.....
        
        
 # 什么时候调用Reqeust的__init__?---》APIVIew的dispatch上面的492行的:request = self.initialize_request(request, *args, **kwargs)-----》385行----》
    def initialize_request(self, request, *args, **kwargs):
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
'我们可以看到就是在给老的request进行包装的时候传入的这个参数'
'接着我们点进get_authenticators方法中查看源码'
        def get_authenticators(self):
        return [auth() for auth in self.authentication_classes]
'这里我们可以看到,跟权限类的源码中相似的部分出现了,就是把视图类中使用的认证类进行加括号然后存放到列表中返回'
'回到上面'
    
 # 总结:
	1 配置在视图类上的认证类,会在执行视图类方法之前执行,在权限认证之前执行
    2 自己写的认证类,可以返回两个值或None
    3 后续可以从request.user 取出当前登录用户(前提是你要在认证类中返回)

3.频率源码分析

前面部分跟权限类的分析流程一样,不做详细解释了,到执行initial方法处为止。

# 之前读过:drf的apiview,在执行视图类的方法之前,执行了3大认证----》dispatch方法中的
    -497行左右, self.initial(request, *args, **kwargs)---》执行3大认证
    
# APIView类的399行左右:
    def initial(self, request, *args, **kwargs):
        # 能够解析的编码,版本控制(知道有这作用就好了,不用管,重点是下面部分)
        self.format_kwarg = self.get_format_suffix(**kwargs)
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

     	# 认证组件的执行位置
        self.perform_authentication(request)
        # 权限组件 
        self.check_permissions(request)
        # 频率组件【读它】
        self.check_throttles(request)
        
        
# APIView 的352行
    def check_throttles(self, request):
        throttle_durations = []
        #self.get_throttles() 这个方法我们也不能一下看出他是什么作用的,但是在这个位置,必然跟前面两个的源码中的代码的作用是类似的,因此我们也要点进源码进行查看(见下方)
        # 配置在视图类上的频率类的对象,放到列表中
        
        # 每次取出一个频率类的对象,执行allow_request方法,这里allow_request方法是存在的,因为我们继承的是SimpleRateThrottle,他内部已经写了一格allow_request方法。如果我们继承BaseThrottle可以在源码中发现allow_request方法是需要我们自行重写的,不然会报错
        # 我们回顾频率类中我们自行重写的方法并没有对频率进行校验,因此我们也可以在源码中看出是allow_request方法进行了校验。
        # allow_request方法的返回值如果是False,访问频率超过了限制,不能再走了
        # allow_request方法的返回值如果是True,没有超出访问频率限制,可以直接往后
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())
'这里的wait()方法和后面的代码的作用可以看接下去的自定义频率类进行对比理解,不展开具体分析了'
        if throttle_durations:
            # Filter out `None` values which may happen in case of config / rate
            # changes, see #1438
            durations = [
                duration for duration in throttle_durations
                if duration is not None
            ]

            duration = max(durations, default=None)
            self.throttled(request, duration)
            

'在get_throttles这个方法中我们可以看到他确实是跟之前一样的作用,把频率类加上括号然后套在列表中返回出来'
            

    def get_throttles(self):
        return [throttle() for throttle in self.throttle_classes]
'返回上面'
            
    
    
'allow_request方法(讲解不详细,后文有详细的分析)'
        def allow_request(self, request, view):
        if self.rate is None:
            return True
		'这里的两个属性通过英文意思我猜测就是检测是否配置了频率要求'
        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True

        self.history = self.cache.get(self.key, [])
        self.now = self.timer()
		'通过自定义频率类的学习,我们可以得知这里的字典是存储频率的检测的时间和计算频率的参数'
        # Drop any requests from the history which have now passed the
        # throttle duration
        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()
        if len(self.history) >= self.num_requests:
            return self.throttle_failure()
        return self.throttle_success()
    '这里就是根据时间范畴对字典中的数据值进行检测,并返回检测结果(布尔值)'
# 总结:
	-我们写的频率类:继承BaseThrottle,重写allow_request,在内部判断,如果超频了,就返回False,如果没超频率,就返回True

4.自定义频率类(了解)

这里咋们了解逻辑,会用代码即可

class SuperThrottle(BaseThrottle):
    VISIT_RECORD = {}
	'从下面的逻辑中我们发现需要有一个访问字典存储ip和被访问的时间,因此需要在这里定义'
    def __init__(self):
        self.history = None
		'这里的history属性同样是因为下方的代码中需要用到才定义的'
    def allow_request(self, request, view):
        # 自己写逻辑,判断是否超频
        # (1)取出访问者ip
        # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 {ip地址:[时间1,时间2,时间3,时间4]}
        # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
        # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
        # (1)取出访问者ip
        ip = request.META.get('REMOTE_ADDR')
        import time
        ctime = time.time()
        # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
        if ip not in self.VISIT_RECORD:
            self.VISIT_RECORD[ip] = [ctime, ]
            return True
        # self.history  = [时间1]
        self.history = self.VISIT_RECORD.get(ip,[])
        # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        while self.history and ctime - self.history[-1] > 60:
            self.history.pop()
        # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
        # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
        if len(self.history) < 3:
            self.history.insert(0, ctime)
            return True
        else:
           
            return False
	'当我们不写下方的wait方法时,我们会发现跟SimpleRateThrottle中编写的allow_request方法有点不同,没有那串英文展示还有多久时间可以继续访问,这里的wait方法就是用于展示那句话的'
    def wait(self):
        import time
        ctime = time.time()
        return 60 - (ctime - self.history[-1])

5 SimpleRateThrottle源码分析

# 写一个频率类,重写allow_request方法,在里面实现频率控制

# SimpleRateThrottle---》allow_request
    def allow_request(self, request, view):
		# 这里就是通过配置文件和scop取出 频率限制是多少,比如一分钟访问5此
        if self.rate is None:
            return True

        # 返回了ip,就以ip做限制
        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True
		# 下面的逻辑,跟咱们写的一样
        self.history = self.cache.get(self.key, [])
        self.now = self.timer()
        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()
        if len(self.history) >= self.num_requests:
            return self.throttle_failure()
        return self.throttle_success()
    
    
    
# SimpleRateThrottle的init方法
    def __init__(self):
        if not getattr(self, 'rate', None):
            # self.rate= '5、h'
            self.rate = self.get_rate()
        
        # 这行代码我们不能直接看懂他的意思,因此需要分析源码(接着看下方的代码)
        # 5    36000
        self.num_requests, self.duration = self.parse_rate(self.rate)
        
        
'在SimpleRateThrottle的init方法中我们发现rate属性是用get_rate方法获取的'
# SimpleRateThrottle的get_rate() 方法
    def get_rate(self):
	'这一块代码就是判断我们有没有设置频率限制(scope属性),如果没有有会报错'
        if not getattr(self, 'scope', None):
            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                   self.__class__.__name__)
            raise ImproperlyConfigured(msg)

        try:
            #  self.scope 是 lqz 字符串
            # 而scope的相关配置信息是需要我们在配置文件中自行设置的
            # 源码就是把他绑定到配置文件中的存有配置信息的字典上:THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
            # return '5/h'
            return self.THROTTLE_RATES[self.scope]
        except KeyError:
            msg = "No default throttle rate set for '%s' scope" % self.scope
            raise ImproperlyConfigured(msg)
'看完之后回到上面的双下init先'  
            
# SimpleRateThrottle的parse_rate 方法
	def parse_rate(self, rate):
        # 这里举例rate的值是'5/h'
        
        # 这里的if是用于处理有scope配置的时候,但配置内容为空的时候的处理方式
        if rate is None:
            return (None, None)
        # num =5
        # period= 'hour'
        # 这里很明显就是进行字符串切割
        num, period = rate.split('/')
        # num_requests=5
        # 这里就是获取频率中的访问次数限制
        num_requests = int(num)
        # 这里就是对频率的时间限制,因为他是用首个字符来进行时分秒的区分的,所以我们之前学习频率组件的时候说时分秒的字符开头对就可以,后面随便写
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
        # (5,36000),这里就是返回频率限制的具体内容了
        return (num_requests, duration)

基于APIView编写分页

分页功能,只有查询所有才有

ps:编写的时候可以吃参照LisAPIView中继承的那个list方法进行参考

    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)

基于APIView编写的list

class BookView(ViewSetMixin, APIView):
    '这里的方法名称必须是list,因为路由在自动自动创建的时候映射也是自动配置的'
    def list(self, request):
        books = Book.objects.all()
        # 使用步骤
        # 1 实例化得到一个分页类的对象
        paginator = CommonLimitOffsetPagination()
        # 2 调用分页类对象的paginate_queryset方法来完成分页(因为源码写了三个参数我们也写三个参数,最后一个参数是view,又因为我们就是在视图配中编写,所以写self就好了),返回的page是 要序列化的数据,分页好的
        page = paginator.paginate_queryset(books, request, self)
        if page is not None:
            serializer = BookSerializer(instance=page, many=True)
            # 我们可以发现源码中显示调用了get_serializer方法,这就是调用序列化类,因此这里我们也可以直接调用序列化类
            
            # 3 返回数据,调用paginator的get_paginated_response方法
            # return paginator.get_paginated_response(serializer.data)
            # 通过查看他的源码我们发现改用Response返回数据的原理(看下方源码和分析)
            return Response({
                'total': paginator.count,
                'next': paginator.get_next_link(),
                'previous': paginator.get_previous_link(),
                'results': serializer.data
            })
            '这里的字典中的键,可以自定义命名,一旦我们更改了这些名字,在postman中接收到的数据的键的名称也会更改'

第二步中需要研究的源码

page = self.paginate_queryset(queryset)

'这里的这个paginate_queryset方法是需要去GenericAPIView中查找的,代码如下:'

    @property
    def paginator(self):
        """
        The paginator instance associated with the view, or `None`.
        """
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        return self._paginator
    
'我们不难发现这个被伪装的paginator其实就是产生一个分页类的对象'
    
    def paginate_queryset(self, queryset):
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
'在最后我们看到了一个熟悉的单词paginate_queryset,这里就相当于是使用分页类产生的对象传入数据进行校验'

第三步中需要研究的源码

    def get_paginated_response(self, data):
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)
    '这里我们可以看到这里跟第二步其实差不多,是获取序列化类产生的对象,然后返回相应的结果,我们通过之前的学习得知返回的结果肯定是Response封装的,因此肯定就是get_paginated_response方法中进行了封装'
    
    
        def get_paginated_response(self, data):
        return Response(OrderedDict([
            ('count', self.page.paginator.count),
            ('next', self.get_next_link()),
            ('previous', self.get_previous_link()),
            ('results', data)
        ]))
        '然后我们在视图类中写了这个方法之后,点进来会看到上方的这个源码,他就是封装了返回的数据的函数,因此我们可以直接给他进行替换,然后对格式进行自定义'