代码之家  ›  专栏  ›  技术社区  ›  KitKit

在django rest框架中重写cursorpagination的页面大小和顺序

  •  0
  • KitKit  · 技术社区  · 6 年前

    我使用django rest框架的cursorpagination,我想覆盖默认值 page_size(10) ordering('timestamp') 在单个视图集中。我该怎么做呢?

    我试过使用我的视图集,但没有成功:

    from rest_framework.pagination import CursorPagination
    class ListAPIView(ListAPIView):
        queryset = Cake.objects.all()
        permission_classes = [AllowAny]
        serializer_class = ListSerializer
        pagination_class = CursorPagination
        filter_backends = (OrderingFilter, DjangoFilterBackend)
        filter_class = CakeListFilter
        filterset_fields = ('cake_type', 'user__username')
        ordering = '-date'
        page_size = 5
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   ivissani    6 年前

    您可以创建一个继承自 CursorPagination 类以设置自定义 page_size 和/或 max_page_size 像这样:

    class CustomPageSizeCursorPagination(CursorPagination):
        page_size = 5
        max_page_size = 100
    

    然后用这个类作为 pagination_class 视图集的字段

    警告:以下代码未经测试

    另一个选项是编写一个自定义分页器类,该类从视图集中获取页面大小。例如:

    class PageSizeInViewSetCursorPagination(CursorPagination):
        def get_page_size(self, request, viewset_page_size):
            if self.page_size_query_param:
                try:
                    return _positive_int(
                        request.query_params[self.page_size_query_param],
                        strict=True,
                        cutoff=self.max_page_size
                    )
                except (KeyError, ValueError):
                    pass
    
            return viewset_page_size or self.page_size
    
        def paginate_queryset(self, queryset, request, view=None):
            # Get the page_size from the viewset and then decide which page_size to use
            viewset_page_size = getattr(view, 'page_size', None) 
            page_size = self.get_page_size(request, viewset_page_size)
    
    
            # What follows is copy/paste of the code from CursorPagination paginate_queryset method
            if not self.page_size:
                return None
    
            self.base_url = request.build_absolute_uri()
            self.ordering = self.get_ordering(request, queryset, view)
    
            self.cursor = self.decode_cursor(request)
            if self.cursor is None:
                (offset, reverse, current_position) = (0, False, None)
            else:
                (offset, reverse, current_position) = self.cursor
    
            # Cursor pagination always enforces an ordering.
            if reverse:
                queryset = queryset.order_by(*_reverse_ordering(self.ordering))
            else:
                queryset = queryset.order_by(*self.ordering)
    
            # If we have a cursor with a fixed position then filter by that.
            if current_position is not None:
                order = self.ordering[0]
                is_reversed = order.startswith('-')
                order_attr = order.lstrip('-')
    
                # Test for: (cursor reversed) XOR (queryset reversed)
                if self.cursor.reverse != is_reversed:
                    kwargs = {order_attr + '__lt': current_position}
                else:
                    kwargs = {order_attr + '__gt': current_position}
    
                queryset = queryset.filter(**kwargs)
    
            # If we have an offset cursor then offset the entire page by that amount.
            # We also always fetch an extra item in order to determine if there is a
            # page following on from this one.
            results = list(queryset[offset:offset + self.page_size + 1])
            self.page = list(results[:self.page_size])
    
            # Determine the position of the final item following the page.
            if len(results) > len(self.page):
                has_following_position = True
                following_position = self._get_position_from_instance(results[-1], self.ordering)
            else:
                has_following_position = False
                following_position = None
    
            # If we have a reverse queryset, then the query ordering was in reverse
            # so we need to reverse the items again before returning them to the user.
            if reverse:
                self.page = list(reversed(self.page))
    
            if reverse:
                # Determine next and previous positions for reverse cursors.
                self.has_next = (current_position is not None) or (offset > 0)
                self.has_previous = has_following_position
                if self.has_next:
                    self.next_position = current_position
                if self.has_previous:
                    self.previous_position = following_position
            else:
                # Determine next and previous positions for forward cursors.
                self.has_next = has_following_position
                self.has_previous = (current_position is not None) or (offset > 0)
                if self.has_next:
                    self.next_position = following_position
                if self.has_previous:
                    self.previous_position = current_position
    
            # Display page controls in the browsable API if there is more
            # than one page.
            if (self.has_previous or self.has_next) and self.template is not None:
                self.display_page_controls = True
    
            return self.page
    

    注意在上面的例子中 页尺寸 request 始终优先于您在代码中设置的任何内容。然后 viewset_page_size 是第二排最后一排 页尺寸 Pagination 班级。