Django的rest_framework的分页组件源码分析

前言:

  分页大家应该都很清楚,今天我来给大家做一下Django的rest_framework的分页组件的分析;我的讲解的思路是这样的,分别使用APIview的视图类和基于ModelViewSet的视图类两种方式实现分页的功能,同时我也会介绍两个分页的类,PageNumberPagination类和LimitOffsetPagination,希望能对大家有所帮助!

  今天的博客主要的这样的,先讲解基于APIView类的两种分页类的实现方式,然后在讲解基于ModelViewSet类的两种分页类的实现方式

正文:

一、基于APIView的视图类,使用PageNumberPagination

1、先导入我们要用到的分页的类

from rest_framework.pagination import PageNumberPagination

  

2、下面我们来看下这个这个类的类是属性

class PageNumberPagination(BasePagination):
    """
    A simple page number based style that supports page numbers as
    query parameters. For example:

    http://api.example.org/accounts/?page=4
    http://api.example.org/accounts/?page=4&page_size=100
    """
    # The default page size.
    # Defaults to `None`, meaning pagination is disabled.
    page_size = api_settings.PAGE_SIZE

    django_paginator_class = DjangoPaginator

    # Client can control the page using this query parameter.
    page_query_param = ‘page‘
    page_query_description = _(‘A page number within the paginated result set.‘)

    # Client can control the page size using this query parameter.
    # Default is ‘None‘. Set to eg ‘page_size‘ to enable usage.
    page_size_query_param = None
    page_size_query_description = _(‘Number of results to return per page.‘)

    # Set to an integer to limit the maximum page size the client may request.
    # Only relevant if ‘page_size_query_param‘ has also been set.
    max_page_size = None

    last_page_strings = (‘last‘,)

    template = ‘rest_framework/pagination/numbers.html‘

    invalid_page_message = _(‘Invalid page.‘)

  

这里我们重点介绍一下类的属性,重点的参数如下,等下我们会测试的

3、然后看下类的paginate_queryset方法,这个方法主要就是用来显示数据的

    def paginate_queryset(self, queryset, request, view=None):
        """
        Paginate a queryset if required, either returning a
        page object, or `None` if pagination is not configured for this view.
        """
        page_size = self.get_page_size(request)
        if not page_size:
            return None

        paginator = self.django_paginator_class(queryset, page_size)
        page_number = request.query_params.get(self.page_query_param, 1)
        if page_number in self.last_page_strings:
            page_number = paginator.num_pages

        try:
            self.page = paginator.page(page_number)
        except InvalidPage as exc:
            msg = self.invalid_page_message.format(
                page_number=page_number, message=six.text_type(exc)
            )
            raise NotFound(msg)

        if paginator.num_pages > 1 and self.template is not None:
            # The browsable API should display pagination controls.
            self.display_page_controls = True

        self.request = request
        return list(self.page)

  

4、PageNumberPagination用到知识点,我们已经讲解完了,下面我们介绍下如何使用,首先我们先继承一下PageNumberPagination,然后自定义我们的参数

class MyPageNumberPagination(PageNumberPagination):
    page_size = 1
    page_query_param = "mypage"
    page_size_query_param = "size"
    max_page_size = 4
    last_page_strings = (‘mylast‘,)

  

5、然后在视图类中使用我们自己写的分页类

class Book_cbv(APIView):
    authentication_classes = []
    # permission_classes = [SVIPpermission(),]
    # throttle_classes = [throttlerate(),]
    # parser_classes = []
    def get(self,request):

        query_list = models.Book.objects.all()
        mypageobj = MyPageNumberPagination()
        obj = mypageobj.paginate_queryset(queryset=query_list,request=request,view=None)
        bs = bookmodelserializer(obj,many=True,context={‘request‘: request})

  

重点看下这里,关注一下paginate_queryset这个方法的参数,和源码中的参数对应一下

源码中的参数

6、下面我们测试一下

每页显示一条数据,显示第一页

每页显示1条数据,显示第二页

类中设定每页显示1条数据,我们临时修改为显示2条数据,显示第一页

类中设定每页显示1条数据,我们临时修改为显示5条数据,显示第一页,理论上5是不生效的,实际只显示了4条数据

经过测试,我们上面的四个参数都已经生效

最后在补充一点,上面的每页显示多少条的设置针对单个表生效,如何基于所有的表生效。

class PageNumberPagination(BasePagination):
    """
    A simple page number based style that supports page numbers as
    query parameters. For example:

    http://api.example.org/accounts/?page=4
    http://api.example.org/accounts/?page=4&page_size=100
    """
    # The default page size.
    # Defaults to `None`, meaning pagination is disabled.
    page_size = api_settings.PAGE_SIZE

  

然后看下api_setttings水里对象

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

  

看下APISettigns这个类

    def __init__(self, user_settings=None, defaults=None, import_strings=None):
        if user_settings:
            self._user_settings = self.__check_user_settings(user_settings)
        self.defaults = defaults or DEFAULTS
        self.import_strings = import_strings or IMPORT_STRINGS
        self._cached_attrs = set()

  

到了这里,我们大致就知道了,我们需要进入我们的project的settings文件中进行设置

REST_FRAMEWORK = {
#     "DEFAULT_AUTHENTICATION_CLASSES":(
#         "app1.utils.Book_auther",
#     ),
#     "DEFAULT_PERMISSION_CLASSES_CLASSES": (
#         "app1.utils.SVIPpermission",
#     ),
#     "DEFAULT_DEFAULT_THROTTLE_CLASSES_CLASSES": (
#         "app1.utils.throttlerate",
#     )
    "PAGE_SIZE" : 2,
}

  

二、基于APIView的视图类,使用LimitOffsetPagination类

1、导入LimitOffsetPagination类

from rest_framework.pagination import LimitOffsetPagination

  

2、我们同样看下这个类的属性

class LimitOffsetPagination(BasePagination):
    """
    A limit/offset based style. For example:

    http://api.example.org/accounts/?limit=100
    http://api.example.org/accounts/?offset=400&limit=100
    """
    default_limit = api_settings.PAGE_SIZE
    limit_query_param = ‘limit‘
    limit_query_description = _(‘Number of results to return per page.‘)
    offset_query_param = ‘offset‘
    offset_query_description = _(‘The initial index from which to return the results.‘)
    max_limit = None
    template = ‘rest_framework/pagination/numbers.html‘

  

重点看下下面几个属性

3、然后看下LimitOffsetPagination类的paginate_queryset的方法

    def paginate_queryset(self, queryset, request, view=None):
        self.count = self.get_count(queryset)
        self.limit = self.get_limit(request)
        if self.limit is None:
            return None

        self.offset = self.get_offset(request)
        self.request = request
        if self.count > self.limit and self.template is not None:
            self.display_page_controls = True

        if self.count == 0 or self.offset > self.count:
            return []
        return list(queryset[self.offset:self.offset + self.limit])

  

4、然后我们看下如何在我们的视图类中使用这个分页插件,其实和前面的插件的用法是一样的,只是参数不一样而已

class Book_cbv(APIView):
    authentication_classes = []
    # permission_classes = [SVIPpermission(),]
    # throttle_classes = [throttlerate(),]
    # parser_classes = []
    def get(self,request):

        query_list = models.Book.objects.all()
        # mypageobj = MyPageNumberPagination()
        # obj = mypageobj.paginate_queryset(queryset=query_list,request=request,view=None)
        mypageobj = MyLimitOffsetPagination()
        obj = mypageobj.paginate_queryset(queryset=query_list,request=request,view=None)
        bs = bookmodelserializer(obj,many=True,context={‘request‘: request})

        return Response(bs.data)

  

重点是这里

5、最后我们测试一下

默认不传参数,每页显示2条

临时修改每页显示为1个,偏移量为1

临时修改每页显示1条,偏移量为2

三、基于ModelViewSet的视图类,实现分页功能

通过上面的讲解,我们知道两个分页的类就是参数不一样,使用的逻辑都一样,我们这里就不分开讲解2个类,只讲一下如何ModelViewSet类实现分页

1、先看下基于ModelViewSet的视图类

from rest_framework import viewsets

class AutherModelCBV(viewsets.ModelViewSet):
    queryset = models.Auther.objects.all()
    serializer_class = authermodelserializer

  

2、因为这个ModelViewSet这个类重写了list方法,分页肯定在list方法中,所以我们先要找到list方法,ModelViewSet这个类一共有4个父类

3、我们看下mixins.ListModelMixin这个类,因为list方法是在这个类中实现的,进入这个类,看下list方法

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)

  

4、重点看下paginate_queryset这个方法,首先要先找到这个方法

5、如果找这个方法呢,我们从最开始找这个方法

首先AutherModelCBV这个类没有这个方法

from rest_framework import viewsets

class AutherModelCBV(viewsets.ModelViewSet):
    queryset = models.Auther.objects.all()
    serializer_class = authermodelserializer

然后去ModelViewSet类中找这个方法,同样没有

class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

  

ModelViewSet这个类继承了有5个类,我们从左到右一个一个看,最终在GenericViewSet,我们看到这个类还继承了2个类

class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
    """
    The GenericViewSet class does not provide any actions by default,
    but does include the base set of generic view behavior, such as
    the `get_object` and `get_queryset` methods.
    """
    pass

  

再次从左到右依次查找paginate_queryset这个方法,最终下面这个类中找到这个方法

class GenericAPIView(views.APIView):

  

方法的源码如下

    def paginate_queryset(self, queryset):
        """
        Return a single page of results, or `None` if pagination is disabled.
        """
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset, self.request, view=self)

  

那么这个paginator是什么呢,原来他是静态方法

    @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

  

到这里,我们就非常清楚的了,我们需要在我们自己的视图类中定义一个这样的属性,然后把我们的分页类赋值给pagination_class这个属性就可以了

6、然后看下在ModelViewSet类中如何操作

from rest_framework import viewsets

class AutherModelCBV(viewsets.ModelViewSet):
    queryset = models.Auther.objects.all()
    serializer_class = authermodelserializer
    pagination_class = MyPageNumberPagination

  

重点看下这里

最后我们测试一下

下面这个是我们禁用分页的显示效果

下面开始启用分页的效果,显示第一页

显示第二页的效果

总结:至此,Django的Rest_framework的分页组件就介绍完了,大家有不清楚的,可以留言,我们共同进步。

原文地址:https://www.cnblogs.com/bainianminguo/p/10508191.html

时间: 2024-08-29 18:19:24

Django的rest_framework的分页组件源码分析的相关文章

django的RBAC认证z;自定义auth_user表;认证组件权限组件源码分析;认证组件;权限组件

一 RBAC 1.RBAC:全称(Role-Based Access Control):指的是基于用户权限访问控制的认证. 2.Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为:三表规则,五表规则:Django采用的是六表规则. # 三表:用户表.角色表.权限表# 五表:用户表.角色表.权限表.用户角色关系表.角色权限关系表# 六表:用户表.角色表.权限表.用户角色关系表.角色权限关系表.用户权限关系表 3.在Django中六表之间是都是多对多的关系,可通过下面字段跨表访问

Django REST framework —— 权限组件源码分析

在上一篇文章中我们已经分析了认证组件源码,我们再来看看权限组件的源码,权限组件相对容易,因为只需要返回True 和False即可 代码 1 class ShoppingCarView(ViewSetMixin, APIView): 2 permission_classes = [MyPermission, ] 3 def list(self,request, *args, **kwargs): 4 """ 5 查看购物车信息 6 :param args: 7 :param k

Django之admin的使用及源码分析

一.admin组件使用 Django本身提供了基于 web 的管理工具.其管理工具是django.contrib的一部分,可在settings.py中的 INSTALLED_APPS 看到: INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'dj

Django的rest_framework的权限组件和频率组件源码分析

前言: Django的rest_framework一共有三大组件,分别为认证组件perform_authentication,权限组件check_throttles: 我在前面的博客中已经梳理了认证组件,不知道大家有没有看懂:在这里我把认证的组件的博客地址在贴出来,不清楚的人可以看下 局部设置认证组件的博客:https://www.cnblogs.com/bainianminguo/p/10480887.html 全局设置认证组件的博客:https://www.cnblogs.com/baini

Spring MVC组件源码分析

组件概览 HandlerMapping 根据 request 找到对应的处理器 Handler 和 Interceptors.内部只有一个方法 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; HandlerAdapter Handler 适配器,内部方法如下: boolean supports(Object handler);//判断是否可以使用某个 Handler ModelAndVi

Django rest framework 限制访问频率(源码分析三)

基于 当用发出请求时 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制 self.initial(request, *args, **kwargs) 进入到initial方法: def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method han

Python学习---Django关于POST的请求解析源码分析

当有请求到来之后,先判断请求头content_type是不是[application/x-www-form-urlencoded] --> 如果是则将请求数据赋值给request.body然后解析为字典形式的数据后赋值给request.post 这样我们就可以用request.POST.get('username")获取数据了 --> 如果不是,则直接将请求数据赋值给request.body之后并不赋值给request.post,此时POST内的数据为空 原文地址:https://w

Django 之restfromwork 源码分析之--视图组件

restframework 源码分析以及使用 mixins 中的五种类方法 from rest_framework import mixins # mixins 中一种有五种类 # 第一种:用户保存数据 class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): # 序列化的类的对象 ser

Django REST framework之序列化组件以及源码分析+全局、局部Hook

序列化两大功能 a.对queryset类型进行序列化 b.对用户请求的数据进行校验 a.对queryset类型进行序列化 举例说明: 表设计 1 from django.db import models 2 3 4 class UserGroup(models.Model): 5 title = models.CharField(max_length=32) 6 7 8 class UserInfo(models.Model): 9 user_type_choices = ( 10 (1, '普