详解Django的 paginate_by() 函数:指定每页显示的数量

  • Post category:Python

paginate_by()函数是Django框架中用于分页的函数,该函数主要作用是将一个查询集(QuerySet)分页展示并提供页面跳转功能。该函数可以在类视图中使用。

使用paginate_by()函数的方法如下:
1. 首先在视图类中定义paginate_by属性,该属性表示每个页面显示的数据条数。
2. 在get_context_data()函数中调用父类方法,并传入paginate_by参数,该参数为每页显示的条数。
3. 在模板中使用模板标签PaginatorPageNotAnInteger来实现分页展示。

下面提供两个实例,分别是列表页和博客文章页的分页展示:

1. 列表页的分页展示

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = 'article_list.html'
    context_object_name = 'articles'
    paginate_by = 10   # 每页展示10条数据

    def get_queryset(self):
        return Article.objects.all().order_by('-id')

上述代码定义了一个名为ArticleListView的类视图,该视图用于展示所有博客文章的列表。在ArticleListView类中,我们定义了paginate_by属性,并且在get_queryset()方法中定义了查询集。

实现分页展示的模板article_list.html如下:

{% extends 'base.html' %}

{% block content %}
  <h2>博客文章列表</h2>
  <div class="row">
    {% for article in articles %}
      <div class="col-sm-6 col-md-4 mb-3">
        <div class="card">
          <div class="card-body">
            <a href="{% url 'article_detail' article.id %}">{{ article.title }}</a>
            <p class="text-muted">{{ article.created_at|date }}</p>
          </div>
        </div>
      </div>
    {% endfor %}
  </div>
  <!-- Pagination -->
  <nav aria-label="Page navigation example">
    <ul class="pagination">
      {% if articles.has_previous %}
        <li class="page-item"><a class="page-link" href="?page={{ articles.previous_page_number }}">上一页</a></li>
      {% else %}
        <li class="page-item disabled"><a class="page-link">上一页</a></li>
      {% endif %}
      {% for i in articles.paginator.page_range %}
        {% if articles.number == i %}
          <li class="page-item active"><a class="page-link">{{ i }}</a></li>
        {% elif i > articles.number|add:-3 and i < articles.number|add:3 %}
          <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
        {% endif %}
      {% endfor %}
      {% if articles.has_next %}
        <li class="page-item"><a class="page-link" href="?page={{ articles.next_page_number }}">下一页</a></li>
      {% else %}
        <li class="page-item disabled"><a class="page-link">下一页</a></li>
      {% endif %}
    </ul>
  </nav>
{% endblock %}

上述模板代码中使用了模板标签PaginatorPageNotAnInteger,其中Paginator用于生成分页逻辑,而PageNotAnInteger用于处理非整数的情况。

2. 博客文章页的分页展示

from django.views.generic import DetailView
from .models import Article, Comment

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'article_detail.html'
    context_object_name = 'article'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        comments = Comment.objects.filter(article=self.object).order_by('-id')
        # 在上下文中加入评论列表
        context['comments'] = self.paginate_comments(comments)
        return context

    def paginate_comments(self, comments):
        paginator = Paginator(comments, 5)  # 每页展示5条评论
        page = self.request.GET.get('page')
        try:
            comments = paginator.page(page)
        except PageNotAnInteger:
            comments = paginator.page(1)
        except EmptyPage:
            comments = paginator.page(paginator.num_pages)
        return comments

上述代码定义了一个名为ArticleDetailView的类视图,该视图用于展示每篇博客文章的详情。在ArticleDetailView类中,我们定义了paginate_comments()方法,并在get_context_data()方法中通过该方法实现评论的分页展示。

实现分页展示的模板article_detail.html如下:

{% extends 'base.html' %}

{% block content %}
  <div class="row">
    <div class="col-md-8">
      <h2>{{ article.title }}</h2>
      <p class="text-muted">{{ article.created_at|date }}</p>
      <p>{{ article.content }}</p>
    </div>
    <div class="col-md-4">
      <div class="card">
        <div class="card-body">
          <h5 class="card-title">评论</h5>
          {% for comment in comments %}
            <div class="card mb-3">
              <div class="card-body">
                <p class="card-text">{{ comment.content }}</p>
                <p class="card-text"><small class="text-muted">{{ comment.created_at|date }}</small></p>
              </div>
            </div>
          {% empty %}
            <p>暂无评论</p>
          {% endfor %}
          <!-- Pagination -->
          {% if comments.has_other_pages %}
            <nav aria-label="Page navigation example">
              <ul class="pagination justify-content-center">
                {% if comments.has_previous %}
                  <li class="page-item"><a class="page-link" href="?page={{ comments.previous_page_number }}">上一页</a></li>
                {% else %}
                  <li class="page-item disabled"><a class="page-link">上一页</a></li>
                {% endif %}
                {% for i in comments.paginator.page_range %}
                  {% if comments.number == i %}
                    <li class="page-item active"><a class="page-link">{{ i }}</a></li>
                  {% elif i > comments.number|add:-3 and i < comments.number|add:3 %}
                    <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                  {% endif %}
                {% endfor %}
                {% if comments.has_next %}
                  <li class="page-item"><a class="page-link" href="?page={{ comments.next_page_number }}">下一页</a></li>
                {% else %}
                  <li class="page-item disabled"><a class="page-link">下一页</a></li>
                {% endif %}
              </ul>
            </nav>
          {% endif %}
        </div>
      </div>
    </div>
  </div>
{% endblock %}

上述模板代码中也使用了模板标签PaginatorPageNotAnInteger,其中Paginator用于生成评论的分页逻辑,而PageNotAnInteger用于处理非整数的情况。

通过以上两个实例,我们可以看出,使用paginate_by()函数可以轻松实现Django框架中的分页功能,提高网站的用户体验。