解读django-drf分页,进行自定义封装分页

django 的drf中自带有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)
def get_paginated_response(self, data):
    """
    Return a paginated style `Response` object for the given output data.
    """
    assert self.paginator is not None
    return self.paginator.get_paginated_response(data)
@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

通过分析源码可以看到list的分页返回是取pagination_class里的get_paginated_response方法
配置方法一:

  • 常规我们会在视图集中进行配置,如下图:
from rest_framework import viewsets
from rest_framework.pagination import PageNumberPagination
class HomeAPIView(viewsets.ModelViewSet):
    queryset = Home.objects.all()
    pagination_class = CoursePageNumberPagination

CoursePageNumberPagination里的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)
    ]))

配置方法二:

  • 我们查看源码可以看到这个地方,就是在我们继承通用视图集中,源码中有个pagination_class属性,我们可以在settings中配置
class GenericAPIView(views.APIView):
    queryset = None
    serializer_class = None
    lookup_field = 'pk'
    lookup_url_kwarg = None
    filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS

配置如下:

REST_FRAMEWORK = {
    "DEFAULT_PAGINATION_CLASS": "component.drf.pagination.CustomPageNumberPagination",
}

再往深点看其实可以看到drf是封装了django.core.paginator
个人开发的时候,有时候写序列化器时,字段查询比较繁琐,就想自己查到数据自己去封装,但是又想格式和drf风格差不多,就自定义封装分页。

from django.core.paginator import Paginator

def my_paginator_response(current_page, page_size, objs):
    """自定义包装返回参数"""
    current_page = int(current_page)
    paginator = Paginator(objs, page_size)
    if current_page not in paginator.page_range:
        current_page = 1
    return dict(
        page=current_page,
        total_page=paginator.num_pages,
        count=paginator.count,
        previous=paginator.page(current_page).previous_page_number()
        if paginator.page(current_page).has_previous()
        else None,
        next=paginator.page(current_page).next_page_number() if paginator.page(current_page).has_next() else None,
        items=paginator.page(current_page).object_list,
    )

使用案例:

from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import Q


class GenericAPIView(views.APIView):
    queryset = Home.objects.all()
    
    @action(methods=["get"], detail=False)
    def get_homes(self, request, *args, **kwargs):
    	home_name = request.query_params.get("home_name")
        current_page = request.query_params.get("current_page", 1)
        page_size = request.query_params.get("page_size", 10)
        q = Q()
        if task_name:
            q &= Q(home_name__icontains=str(home_name))
        checktasks = CheckTask.objects.filter(q)
        resp_data = my_paginator_response(current_page,page_size,checktasks)
    	# 如果需要特殊序列化数据可以取出来
    	for item in resp_data['items']:
    		# do somethings
    		pass
    	return Response(resp_data)

你可能感兴趣的:(django框架,django,python)