You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF CursorPagination多排序字段与过滤组合致上一页空结果问题

DRF CursorPagination 结合过滤器时返回空previous页的问题解决

问题现象

使用Django Rest Framework(DRF)的CursorPagination搭配过滤器时出现异常:访问端点初始页能获取到next URL,访问该next URL后会生成previous URL,但点击这个previous URL却返回空的结果列表。

排查发现:虽然分页类中配置了多字段排序(date, custom_channel_name, country_name, platform_type_code, id),但解码后的previous游标仅包含date字段;查看DRF源码后确认,默认的_get_position_from_instance方法只提取排序配置中的第一个字段值。当存在重复的date值时,过滤后的分页定位逻辑会出错,导致previous页无法正确匹配数据。

用户相关代码:

class RevenuePagination(CursorPagination):
    page_size = 200
    ordering = ['date', 'custom_channel_name', 'country_name', 'platform_type_code', 'id']


class RevenueFilter(django_filters.FilterSet):
    class Meta:
        model = Revenue
        fields = {
            'date': ['lte', 'gte'],
            'custom_channel_name': ['exact'],
            'country_name': ['exact'],
            'platform_type_code': ['exact'],
        }


class RevenueViewSet(viewsets.ModelViewSet):
    permission_classes = [HasAPIKey]
    queryset = Revenue.objects.all()
    serializer_class = RevenueSerializer
    filterset_class = RevenueFilter
    pagination_class = RevenuePagination

    @revenue_list_schema()
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)

解决方案

重写CursorPagination的_get_position_from_instance方法,让它收集所有排序字段的值,而不是只取第一个。这样即使date字段有重复,后续的唯一字段(比如id)能确保游标准确定位,避免分页逻辑出错。

修改后的分页类代码:

class RevenuePagination(CursorPagination):
    page_size = 200
    ordering = ['date', 'custom_channel_name', 'country_name', 'platform_type_code', 'id']

    def _get_position_from_instance(self, instance):
        position = []
        for field in self.ordering:
            # 处理降序排序的情况(如果排序字段带'-'前缀)
            if field.startswith('-'):
                field_name = field[1:]
                # 数值型字段取反,非数值型直接取值(可根据实际场景调整)
                field_value = getattr(instance, field_name)
                value = -field_value if isinstance(field_value, (int, float)) else field_value
            else:
                value = getattr(instance, field)
            position.append(value)
        return position

说明

  • 上述代码会遍历所有配置的排序字段,将每个字段的值都加入到游标位置中,确保游标能唯一标识数据行的位置。
  • 如果排序字段包含外键或其他需要特殊处理的字段,需要调整getattr的取值逻辑,比如外键字段可以取instance.foreign_key.id来获取主键值。

内容的提问来源于stack exchange,提问作者Martin Taleski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:42:11