【问题标题】:Django DRF incorrect pagination countDjango DRF 不正确的分页计数
【发布时间】:2021-05-21 08:05:08
【问题描述】:

我为我的 django drf 应用程序使用了一个自定义但简单的分页类:

from rest_framework.pagination import PageNumberPagination

class CustomPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = "page_size"
    max_page_size = 100

我还有一个 ViewSet 操作,它对继承的查询集执行一些操作并返回分页结果:

class MatchOfJobViewSet(ModelViewSet):

  serializer_class = MatchSerializer
  filter_backends = (DjangoFilterBackend,)

  # classic filter inheriting from django_filter.FilterSet
  filter_class = MatchFilter

  def get_queryset(self):
    job_pk = self.kwargs["job_pk"]
    return Match.objects.filter(job_pk=job_pk)

  @action(
    detail=False,
    methods=["get"],
    url_path="dynamic",
    serializer_class=MatchDynamicSerializer
  )
  def dynamic(self, request, *args, other_args, **kwargs):
    """return the list of matches with a dynamic serializer"""

    # some operation on the queryset
    queryset = self.get_queryset().select_related("some_field")

    # apply the filters
    queryset = self.filter_queryset(queryset)

    # paginate
    page = self.paginate_queryset(queryset)

    # I use a custom serializer that takes extra arguments
    # to update dynamically the fields to be serialized
    serializer = self.get_serializer(page, many=True, other_args=other_args)

    # unchanged from the generic list response
    return self.get_paginated_response(serializer.data)

我从视图中得到的响应是这样的

{
  "count": 308,
  "next": "https://blabla.com?page=2&page_size=100",
  "previous": "https://blabla.com?page=4&page_size=100",
  "results": [...]
}

计数显示 308 个条目虽然我在数据库中签入时只有 297 个条目(这导致最后一页最终为空)

从我读到的count 参数是由分页器(这是默认的DjangoPaginator)使用相同的查询集计算的。评估后的查询集和 Paginator.count() 如何给出不同的结果?

【问题讨论】:

  • 在表格中可能是297 行,这并不意味着分页类中的QuerySet.count() 必须返回相同的数字。也就是说,您的 QuerySet 可能包含一些重复的行。
  • 我可以看到您一直在使用filter_backends,这可能会导致重复
  • 告诉我们MatchFilter,我相信那里会发生一些事情。就像过滤多对多关系并获得多个重复结果一样。
  • 这是真的,过滤器可能会重复条目。我将检查添加 distinct(id) 是否会改变任何内容。但是它有重复的行,最后一页不会是空的,对吧?

标签: python django django-rest-framework django-pagination


【解决方案1】:

感谢评论,我发现queryset.count()len(queryset) 之间的差异是由我的get_queryset() 方法中应用的一些注释引起的。

我认为使用queryset.query.annotations.clean() 会完全从 SQL 查询中清除它,但它留下了一些痕迹,尤其是一些 OUTTER LEFT JOIN。这导致 COUNT SQL 查询对条目进行多次计数。

如果您最终遇到类似问题,我建议您仔细检查应用于您的查询集的过滤器和注释。您可以使用this ticket 中的方法检查.count() 运行的SQL 查询

【讨论】:

    猜你喜欢
    • 2011-03-30
    • 2015-12-12
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 2014-04-20
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多