最新消息:20210917 已从crifan.com换到crifan.org

【已解决】Django中如何自定义返回分页数据

数据 crifan 744浏览 0评论
折腾:
【已解决】Antd Pro中前端列表页面loading加载很慢
期间,现在需要去Django中自定义返回分页数据,以便于前后端搭配,实现返回需要的数据
所以,现在就是去想办法让返回的数据,在当传入:
scripts/?page=2&page_size=20
时,不是返回所有的数据,而只是返回第一页的20个的数据
所以去后台Django中,去改代码
后端代码原先是:
    def list(self, request, *args, **kwargs):
        """
            获取 script list,取 author=request.user。按历史记录 version 最新的一个script,
            组成列表
        """
        logger.info("ScriptViewSet list: request=%s", request)

        filterAuthorList = []

        reqUser = request.user
        logger.info("reqUser=%s", reqUser)

        if reqUser.is_superuser :
            # is superuser, means get all script list, so not filter himself
            filterAuthorList = []
        else:
            filterAuthorList = [reqUser]

        # if pass in author_id or group_id, take precedence for filter author over request user
        authorId = request.query_params.get('author_id', '')
        groupId = request.query_params.get('group_id', '')
        logger.info("authorId=%s, groupId=%s", authorId, groupId)
        if authorId:
            passInAuthor = User.objects.get(pk=authorId)
            logger.info("passInAuthor=%s", passInAuthor)
            if passInAuthor:
                filterAuthorList = [passInAuthor]
        elif groupId:
            passInGroup = FunctionGroup.objects.get(pk=groupId)
            logger.info("passInGroup=%s", passInGroup)
            if passInGroup:
                membersRelatedManager = passInGroup.members
                logger.info("membersRelatedManager=%s", membersRelatedManager)
                logger.info("type(membersRelatedManager)=%s", type(membersRelatedManager))
                memberList = membersRelatedManager.all()
                logger.info("memberList=%s", memberList)
                filterAuthorList = memberList

        logger.info("len=%d, filterAuthorList=%s", len(filterAuthorList), filterAuthorList)

        userFilter = Q()
        if filterAuthorList:
            userFilter = Q(author__in=filterAuthorList)
        logger.info("userFilter=%s", userFilter)

        filterByUserScriptList = Script.objects.filter(userFilter)
        logger.info("filterByUserScriptList=%s", filterByUserScriptList)
        filterByUserScriptListLen = len(filterByUserScriptList)
        logger.info("filterByUserScriptListLen=%s", filterByUserScriptListLen)

        filter_condition = self.generateQueryFilterCondiction(request)
        logger.info("filter_condition=%s", filter_condition)
        result = []
        historyIdList = []
        for curScriptIdx, singleScript in enumerate(filterByUserScriptList):
            logger.info("---[%d] singleScript=%s", curScriptIdx, singleScript)
            scriptHistoryId = singleScript.history_id
            logger.info("scriptHistoryId=%s", scriptHistoryId)
            if scriptHistoryId not in historyIdList:
                historyIdList.append(singleScript.history_id)

        logger.info("historyIdList=%s", historyIdList)
        historyIdListLen = len(historyIdList)
        logger.info("historyIdListLen=%s", historyIdListLen)

        for curHisotryIdIdx, eachHistoryId in enumerate(historyIdList):
            logger.info("===[%d] eachHistoryId=%s", curHisotryIdIdx, eachHistoryId)
            history = History.objects.get(pk=eachHistoryId)
            logger.info("history=%s", history)
            orderedScriptAllHistory = history.script_history.all().order_by('version')
            logger.info("orderedScriptAllHistory=%s", orderedScriptAllHistory)
            lastHistory = orderedScriptAllHistory.last()
            logger.info("lastHistory=%s", lastHistory)
            result.append(lastHistory.id)

        logger.info("result=%s", result)
        resultLen = len(result)
        logger.info("resultLen=%s", resultLen)

        queryset = Script.objects.filter(pk__in=result).filter(filter_condition).order_by('-created_at')
        logger.info("queryset=%s", queryset)
        page = self.paginate_queryset(queryset)
        logger.info("page=%s", page)

        serializer = ScriptSerializer(queryset, many=True)
        logger.info("after ScriptSerializer serializer=%s", serializer)
        serializedData = serializer.data
        logger.info("serializedData=%s", serializedData)

        respData = None
        if page is not None:
            respData = self.get_paginated_response(serializedData)
        else:
            respData = Response(serializedData)

        logger.info("respData=%s", respData)
        return respData
现在要去改为支持传入的page和pagesize,返回对应page的值
经过调试发现返回的:
INFO|20180810 17:22:02|views:list:186|serializedData=[OrderedDict([('id', 'cb54d47d-6e9c-4ec2-8666-eb97df30e654'), ('place', 'cort'), ('title', 'play body'), ('topic', 'Shopping'), ('second_level_topic', 'cake shop'), ('age_start', 3), ('version', 1), ('age_end', 5), ('author', 'Maggie'), ('joinedScriptGroup', {'groupId': 5, 'groupName': 'maggie剧本组'}), ('publish_status', '未发布'), ('edit_status', '未提交'), ('review', None), ('dialog_count', 6), ('created_at', '2018-08-10 14:42:01'), ('updated_at',
...
就是一个数组,然后调用了:self.get_paginated_response
所以要去搞清楚:get_paginated_response
Django get_paginated_response
Pagination – Django REST framework
python 2.7 – “get_paginated_response” in django-rest-framework 3.0 – Stack Overflow
现在需要实现:
返回的数据中包含:
{
  "totalCount": 519,
  "currentPageCount": 20,
  "currentPageNumber": 4,
  "maxPageNumber": 26,
  "next": "
https://api.example.org/accounts/?page=5
",
  "previous": "
https://api.example.org/accounts/?page=3
",
  "results": [
    {},
    {},
    {}
  ]
}
而现有的pagination的class是:
/apps/core/pagination.py
from rest_framework.pagination import PageNumberPagination

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 1000
需要去改造
且只返回当前页的数据
Django-Rest frameworw之分页 – CSDN博客
Django-restframework25 Pagination(分页) – CSDN博客
http://www.django-rest-framework.org/api-guide/pagination/#custom-pagination-styles
想要参考代码去自定义,但是需要获取当前page的值
搜到paginator去参考代码:
        page = request.query_params.get('page', 1)
        page_size = request.query_params.get('page_size', 20)
        p = Paginator(file_list, page_size)
        count = p.count
        current_page = p.page(page)
        if current_page.has_next():
            next = api_url + str(current_page.next_page_number())
        else:
            next = None
        if current_page.has_previous():
            previous = api_url + str(current_page.previous_page_number())
        else:
            previous = None
        current_page_object = current_page.object_list
        format_current_page_object = []
        for j in current_page_object:
            item = {}
            item['id'] = j[0]
            item['name'] = j[1]
            format_current_page_object.append(item)

        return Response({
            "count": count,
            "next": next,
            "previous": previous,
            "results": format_current_page_object
        }, status=status.HTTP_200_OK)
去找找如何写代码,获取current的page
django pagination get current page number
Django pagination and “current page” – Stack Overflow
python – django paginator – how to show all page numbers available – Stack Overflow
Display only some of the page numbers by django pagination – Stack Overflow
python – Get current page of pagination in view and manually set count of page – Stack Overflow
Getting the current page number — Django Endless Pagination 2.0 documentation
How could I get the current page number when paginating? · Issue #161 · dustinfarris/ember-django-adapter · GitHub
How to Paginate with Django
Pagination | Django documentation | Django
Pagination | Django documentation | Django
实在不行,就自己参考上面的自己去返回自己要的效果
【已解决】Django中获取当前配置的参数出错:AttributeError dict object has no attribute
然后想要通过:
/apps/core/pagination.py
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response

import logging
logger = logging.getLogger('django')

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 1000

class CustomPagination(PageNumberPagination):
    page_size = 20
    page_size_query_param = 'page_size'
    max_page_size = 1000

    def get_paginated_response(self, data, curPageNum):
        # respDict = {
        #     'next': self.get_next_link(),
        #     'previous': self.get_previous_link(),
        #     'count': self.page.paginator.count,
        #     'results': data
        # }
        logger.info("CustomPagination get_paginated_response: self=%s,data=%s,curPageNum=%s", self, data, curPageNum)

        logger.info("type(self)=%s", type(self))
        logger.info("type(data)=%s", type(data))

        logger.info("self.page=%s", self.page)
        logger.info("self.page.paginator=%s", self.page.paginator)

        totalCount = self.page.paginator.count
        logger.info("totalCount=%s", totalCount)
        maxPageCount = self.page.paginator.num_pages
        logger.info("maxPageCount=%s", maxPageCount)

        curPage = self.page.paginator.page(curPageNum)
        logger.info("curPage=%s", curPage)
        logger.info("type(curPage)=%s", type(curPage))
        curPageItemList = curPage.object_list
        logger.info("curPageItemList=%s", curPageItemList)
        currentPageCount = len(curPageItemList)
        logger.info("currentPageCount=%s", currentPageCount)

        nextPageUrl = self.get_next_link()
        previousPageUrl = self.get_previous_link()

        respDict = {
            "totalCount": totalCount,
            "maxPageCount": maxPageCount,
            "currentPageNumber": curPageNum,
            "currentPageCount": currentPageCount,
            "next": nextPageUrl,
            "previous": previousPageUrl,
            "results": curPageItemList
        }

        return Response(respDict)
然后去调用:
apps/script/views.py
    def list(self, request, *args, **kwargs):
        if paginatedQueryset is not None:
            # respData = self.get_paginated_response(serializedData)
            respData = self.get_paginated_response(serializedData, page)
结果提示出错:
  File "/Users/crifan/dev/dev_root/company/xxx/projects/xxx/server/xxx/apps/script/views.py", line194, in list
    respData = self.get_paginated_response(serializedData, page)
TypeError: get_paginated_response() takes 2 positional arguments but 3 were given
因为是继承的函数只有2个参数:
/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/generics.py
  class GenericAPIView(views.APIView):

    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)
所以没法添加当前page的number
感觉只能放弃这条路。
django pagination return current page data
python – Django Pagination Current page in View.py – Stack Overflow
好像只能用Paginator只能去生成结果了?
Reversing results for current page (django paginator generic view) – Stack Overflow
django paginate current page data
python – Get current page of pagination in view and manually set count of page – Stack Overflow
好像自定义Pagenation的类中,可以获取request?
这样就可以获取page参数了。
去试试
然后发现了:
/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/rest_framework/generics.py
    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)
即:paginate_queryset带了self.request-》可以获取到page参数的
Django pagination and “current page” – Stack Overflow
Display only some of the page numbers by django pagination – Stack Overflow
pagination – How to paginate Django with other get variables? – Stack Overflow
不过还是之前的代码,发现在CustomPagination的get_paginated_response中,是可以获得当前page的:
INFO|20180810 21:51:34|pagination:get_paginated_response:28|type(self)=<class 'apps.core.pagination.CustomPagination'>
INFO|20180810 21:51:34|pagination:get_paginated_response:29|type(data)=<class 'rest_framework.utils.serializer_helpers.ReturnList'>
INFO|20180810 21:51:34|pagination:get_paginated_response:31|self.page=<Page 1 of 26>
INFO|20180810 21:51:34|pagination:get_paginated_response:32|self.page.paginator=<django.core.paginator.Paginator object at 0x109bb1e48>
INFO|20180810 21:51:34|pagination:get_paginated_response:35|totalCount=519
INFO|20180810 21:51:34|pagination:get_paginated_response:37|maxPageCount=26
那么后面就可以去只返回当前page的数据了。
而当前的page页数,可以通过:
Django pagination and “current page” – Stack Overflow
-》
“Attributes¶
Page.object_list¶
The list of objects on this page.
Page.number¶
The 1-based page number for this page.
Page.paginator¶
The associated Paginator object.”
的.number去获得
结果返回:
curPageItemList = curPage.object_list
logger.info("curPageItemList=%s", curPageItemList)

        respDict = {
            "totalCount": totalCount,
            "maxPageCount": maxPageCount,
            "currentPageNumber": curPageNum,
            "currentPageCount": currentPageCount,
            "next": nextPageUrl,
            "previous": previousPageUrl,
            "results": curPageItemList
        }
结果报错:
  File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'Script' is not JSON serializable
而改为:
curPageItemList = data
logger.info("curPageItemList=%s", curPageItemList)
currentPageCount = len(curPageItemList)
logger.info("currentPageCount=%s", currentPageCount)
结果虽然没报错,又是回到了之前:返回了所有的数据
而如果想要在get_paginated_response中调用此处的
serializer = ScriptSerializer(queryset, many=True)
logger.info("after ScriptSerializer serializer=%s", serializer)
serializedData = serializer.data
logger.info("serializedData=%s", serializedData)
去序列化-》则又会出现:
不知道实际上是哪个类的Serializer
而且本身很麻烦,干脆直接放弃get_paginated_response,自己用Paginator就好了
【总结】
目前把代码改为:
from django.core.paginator import Paginator
from rest_framework.response import Response

        serializer = ScriptSerializer(queryset, many=True)
        logger.info("after ScriptSerializer serializer=%s", serializer)
        serializedData = serializer.data
        logger.info("serializedData=%s", serializedData)

        # respDict = None
        # if paginatedQueryset is not None:
        #     respDict = self.get_paginated_response(serializedData)
        #     # respDict = self.get_paginated_response(serializedData, page)
        # else:
        #     respDict = Response(serializedData)

        # logger.info("respDict=%s", respDict)
        # return respDict

        curPaginator = Paginator(serializedData, page_size)
        logger.info("curPaginator=%s", curPaginator)
        totalCount = curPaginator.count
        logger.info("totalCount=%s", totalCount)
        maxPageCount = curPaginator.num_pages
        logger.info("maxPageCount=%s", maxPageCount)

        curPageNum = page
        logger.info("curPageNum=%s", curPageNum)
        curPage = curPaginator.page(curPageNum)
        logger.info("curPage=%s", curPage)
        logger.info("type(curPage)=%s", type(curPage))

        curPageItemList = curPage.object_list
        logger.info("curPageItemList=%s", curPageItemList)
        currentPageCount = len(curPageItemList)
        logger.info("currentPageCount=%s", currentPageCount)

        # nextPageUrl = self.get_next_link()
        # previousPageUrl = self.get_previous_link()
        nextPageUrl = None
        previousPageUrl = None

        respDict = {
            "totalCount": totalCount,
            "maxPageCount": maxPageCount,
            "pageSize": page_size,
            "currentPageNumber": curPageNum,
            "currentPageCount": currentPageCount,
            "next": nextPageUrl,
            "previous": previousPageUrl,
            "results": curPageItemList
        }

        return Response(respDict, status=status.HTTP_200_OK)
可以对于:
127.0.0.1 – – [10/Aug/2018 22:39:20] “GET /api/v1/scripts/?page=3&page_size=20 HTTP/1.1” 200 –
返回:
当前页,只有20个数据:
而不是所有的数据。
暂时凑合满足需求了。

转载请注明:在路上 » 【已解决】Django中如何自定义返回分页数据

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
89 queries in 0.199 seconds, using 20.19MB memory