详解Django的 paginate_queryset() 函数:对查询结果进行分页

  • Post category:Python

paginate_queryset() 函数是 Django 框架中用来实现分页功能的函数。它的主要作用是将一个可迭代的对象进行分页处理,返回当前页的数据以及上一页和下一页页码的信息。搭配着 Django 自带的分页器 Paginator 和视图 ListView 使用,是一个非常方便的分页工具。

函数签名

def paginate_queryset(self, queryset, page_size):
    """
    Paginate the queryset, if needed.

    If the queryset is already sliced, it can be used as-is.
    """
  • queryset: 要进行分页的对象,一般是 QuerySet。
  • page_size: 每页的数据条数。

使用方法

我们主要使用 Django 自带的 Paginator 和视图 ListView 来使用 paginate_queryset() 函数。

在一般的视图函数中使用:

from django.core.paginator import Paginator
from django.shortcuts import render


def myview(request):
    queryset = MyModel.objects.all()
    paginator = Paginator(queryset, 20) # 每页显示20条数据
    page = request.GET.get('page')
    queryset = paginator.get_page(page)
    return render(request, 'my_template.html', {'queryset': queryset})

在类视图 ListView 中使用:

from django.core.paginator import Paginator
from django.views.generic import ListView
from myapp.models import MyModel


class MyListView(ListView):
    model = MyModel
    template_name = 'my_template.html'
    context_object_name = 'queryset'
    paginate_by = 20

    def get_queryset(self):
        queryset = super().get_queryset()
        page = self.request.GET.get('page')
        paginator = Paginator(queryset, self.paginate_by)
        queryset = paginator.get_page(page)
        return queryset

在以上示例代码中,我们都通过 Paginator 来将数据进行分页处理,并通过 paginate_queryset() 函数进行分页操作。其中,ListView 已经默认实现了分页逻辑,我们只需要设置好 paginate_by 属性即可。

实例演示

以用户表为例,假设有 30 条记录,我们将其默认每页显示 10 条。

# views.py
from django.core.paginator import Paginator
from django.shortcuts import render
from myapp.models import User


def user_list(request):
    users = User.objects.all()

    # 分页操作
    paginator = Paginator(users, 10)
    page_num = request.GET.get('page')
    page_users = paginator.get_page(page_num)

    return render(request, 'user_list.html', {'users': page_users})
<!-- templates/user_list.html -->
{% extends 'base.html' %}

{% block content %}
  {% for user in users %}
    <p>{{ user.username }}</p>
  {% endfor %}

  <!-- 显示分页链接 -->
  <div class="pagination">
      <span class="step-links">
          {% if users.has_previous %}
              <a href="?page=1">&laquo; 第一页</a>
              <a href="?page={{ users.previous_page_number }}">上一页</a>
          {% endif %}

          <span class="current-page">
              第{{ users.number }}页,共{{ users.paginator.num_pages }}页
          </span>

          {% if users.has_next %}
              <a href="?page={{ users.next_page_number }}">下一页</a>
              <a href="?page={{ users.paginator.num_pages }}">最后一页 &raquo;</a>
          {% endif %}
      </span>
  </div>
{% endblock %}

我们请求 user_list 视图页面,输出如下:

user1
user2
user3
user4
user5
user6
user7
user8
user9
user10

此时页面下方会展示分页链接,如下所示:

<< 第一页, < 上一页, 第1页,共3页, 下一页 >, 最后一页 >> 

作为第二个实例,如果我们有基于类视图的用户表视图,则可以使用 ListView 视图进行渲染页面。代码如下:

from django.core.paginator import Paginator
from django.views.generic import ListView
from myapp.models import User


class UserListView(ListView):
    model = User
    template_name = 'user_list.html'
    context_object_name = 'users'
    paginate_by = 10

    def get_queryset(self):
        return super().get_queryset().order_by('id')

这样与普通函数类似, ListView 视图会自动进行分页和展示分页链接等操作。