如何在不断变化的数据集上实现 Django 分页

51 阅读3分钟

在 Django 的某个页面上,我想要显示已排序对象列表的子集。相关对象的整个列表非常长,并且在用户查看页面时很有可能发生变化。我不介意页面不是最新的,但我确实需要确保当用户转到下一页时,用户将看到原始排序列表中的下一个 n 个对象。因此,由于数据可能发生变化,使用 Django 的内置分页或 Django-endless-pagination 这类十分出色的库在转到“下一页”时不会返回正确的结果。

huake_00063_.jpg 为了举例说明我的意思,假设我们有对象 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],并想要从小到大排序后每页显示 5 个对象。第一页将如下所示:

1, 2, 3, 4, 5

但是,在查看此页面时,3 和 4 被删除了。如果我们转到“下一页”,分页将重新查询该集合并返回:

8, 9, 10, 11, 12

我意识到这是分页的预期行为,但我希望找到一种简单的方法来使下一页显示:

6, 7, 8, 9, 10

最显而易见的方法是进行一些客户端分页,我意识到有一个很好的 jQuery 库可以实现此目的,但对象的数量可能太大,以至于这种解决方案无法实现。

有没有一种简单的方法可以在查询集上进行分页,并继续使用原始查询集返回的结果,而不是重新获取可能已更改的查询集?

非常感谢您能为我提供任何见解!

2、解决方案

一种可能的解决方案是创建自己的分页函数,该函数不是将下一个链接指向某个页面,而是可以传递一条记录,该记录是下一页的顶级记录。问题是,这仅适用于要添加/更改的项目只是列表中的第一个项目的情况。

以下是如何创建您自己的分页函数的示例:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def custom_pagination(request, queryset, per_page, top_record):
    """
    Custom pagination function that uses a top record to determine the next page.

    Args:
        request: The current request object.
        queryset: The queryset to paginate.
        per_page: The number of objects to display per page.
        top_record: The top record of the next page.

    Returns:
        A paginator object.
    """

    paginator = Paginator(queryset, per_page)
    page_number = 1

    # Determine the page number based on the top record.
    for page in paginator.page_range:
        if page.object_list[0] == top_record:
            page_number = page.number
            break

    # Get the current page.
    try:
        page = paginator.page(page_number)
    except (EmptyPage, PageNotAnInteger):
        page = paginator.page(1)

    # Return the paginator object.
    return paginator, page

您可以在视图中使用此自定义分页函数如下所示:

from django.shortcuts import render

def my_view(request):
    """
    A view that uses the custom pagination function.

    Args:
        request: The current request object.

    Returns:
        An HTTP response.
    """

    # Get the queryset to paginate.
    queryset = MyModel.objects.all()

    # Get the top record of the next page.
    top_record = request.GET.get('top_record', None)

    # Create the paginator object.
    paginator, page = custom_pagination(request, queryset, 5, top_record)

    # Render the template.
    return render(request, 'my_template.html', {'paginator': paginator, 'page': page})

这将允许您在不断变化的数据集上实现分页,而无需担心重新获取查询集。