【问题标题】:Display only some of the page numbers by django pagination通过 django 分页仅显示部分页码
【发布时间】:2015-09-01 01:27:44
【问题描述】:

我在模板中使用 django 分页器。它工作正常,但当有大量页面时效果不佳。

views.py:

def blog(request):
    blogs_list = Blog.objects.all()

    paginator = Paginator(blogs_list, 1)

    try:
        page = int(request.GET.get('page', '1'))
    except:
        page = 1

    try:
        blogs = paginator.page(page)
    except(EmptyPage, InvalidPage):
        blogs = paginator.page(page)
    return render(request, 'blogs.html', {
        'blogs':blogs
        })

模板的sn-p:

  <div class="prev_next">

    {% if blogs.has_previous %}
      <a class="prev btn btn-info" href="?page={{blogs.previous_page_number}}">Prev</a>
    {% endif %}
    {% if blogs.has_next %}
      <a class="next btn btn-info" href="?page={{blogs.next_page_number}}">Next</a>
    {% endif %}
    <div class="pages">
      <ul>
      {% for pg in blogs.paginator.page_range %}
        {% if blogs.number == pg %}
          <li><a href="?page={{pg}}" class="btn btn-default">{{pg}}</a></li>
        {% else %}
          <li><a href="?page={{pg}}" class="btn">{{pg}}</a></li>
        {% endif %}
      {% endfor %}
      </ul>
    </div>
    <span class="clear_both"></span>

  </div> 

现在看起来像这样:

我该怎么做才能只显示 7 个页码而不是全部从当前页码开始,像这样:

Prev 1 (2) 3 4 5 Next

我希望我很清楚,如果没有,请询​​问。非常感谢您的帮助和指导。谢谢。

【问题讨论】:

    标签: django django-pagination


    【解决方案1】:

    要把这个扔进去。我想出了它,因为它让你知道两边还​​有更多的页面。

    <ul class="pagination">
    
    {% if page_obj.has_previous %}
        <li><a href="?page={{ page_obj.previous_page_number }}"><i class="fa fa-chevron-left" aria-hidden="true"></i></a></li>
    {% else %}
        <li class="disabled"><span><i class="fa fa-chevron-left" aria-hidden="true"></i></span></li>
    {% endif %}
    
    {% if page_obj.number|add:'-4' > 1 %}
        <li><a href="?page={{ page_obj.number|add:'-5' }}">&hellip;</a></li>
    {% endif %}
    
    {% for i in page_obj.paginator.page_range %}
        {% if page_obj.number == i %}
            <li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
        {% elif i > page_obj.number|add:'-5' and i < page_obj.number|add:'5' %}
            <li><a href="?page={{ i }}">{{ i }}</a></li>
        {% endif %}
    {% endfor %}
    
    {% if page_obj.paginator.num_pages > page_obj.number|add:'4' %}
        <li><a href="?page={{ page_obj.number|add:'5' }}">&hellip;</a></li>
    {% endif %}
    
    {% if page_obj.has_next %}
        <li><a href="?page={{ page_obj.next_page_number }}"><i class="fa fa-chevron-right" aria-hidden="true"></i></a></li>
    {% else %}
        <li class="disabled"><span><i class="fa fa-chevron-right" aria-hidden="true"></i></span></li>
    {% endif %}
    
    </ul>
    

    它看起来像这样:

    【讨论】:

    • 优秀的答案!基于这个答案,我创建了一个具有相同结果的模板标签。
    • 太棒了!这也适用于基于通用类的视图。
    • 这太棒了!感谢您分享这个,这使我免于使用包裹或不得不围绕这个包裹我的大脑。 (在 Django 2.2 上使用)
    • 这太棒了!!非常感谢!
    • 如何响应移动设备?
    【解决方案2】:

    另一个使用模板的更短的解决方案是将当前的 forloop.counter 与特定范围进行比较。

    通过引导我使用这个模板

    <nav aria-label="Page navigation">   <ul class="pagination">
    {% if page_obj.has_previous %}
    <li class="page-item">
      <a class="page-link" href="?page=1" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
        <span class="sr-only">begin</span>
      </a>
    </li>   {% endif %}
    
    {% for n in page_obj.paginator.page_range %}
      {% if page_obj.number == n %}
        <li class="page-item active">
          <span class="page-link">{{ n }}<span class="sr-only">(current)</span></span>
        </li>
      {% elif n > page_obj.number|add:'-3' and n < page_obj.number|add:'3' %}
        <li class="page-item"><a class="page-link" href="?page={{ n }}">{{ n }}</a></li>
      {% endif %}
    {% endfor %}
    
    {% if page_obj.has_next %}
      <li class="page-item">
        <a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Next">
          <span aria-hidden="true">&raquo;</span>
          <span class="sr-only">end</span>
        </a>
      </li>
      {% endif %}   </ul> </nav>
    

    【讨论】:

    • 我最喜欢这个答案,更短更容易理解\
    • 这是最简单的方法,对我有帮助,非常感谢
    • (避免在页面之间重复第一页和最后一页)第 15 行替换为:` {% if n != 1 and n != page_obj.paginator.num_pages %}
    • {{ n }
    • {% endif %} `
  • 这是一个非常非常非常简单的解决复杂问题的明智答案
  • 简单的方法帮助了我很多。干杯!
  • 【解决方案3】:

    首先,我将更改以下内容:

    try:
        blogs = paginator.page(page)
    except(EmptyPage, InvalidPage):
        blogs = paginator.page(page)  # Raises the same error
    

    但是你可以在你的上下文中传递一个范围。

    index = paginator.page_range.index(blogs.number)
    max_index = len(paginator.page_range)
    start_index = index - 3 if index >= 3 else 0
    end_index = index + 3 if index <= max_index - 3 else max_index
    page_range = paginator.page_range[start_index:end_index]
    

    现在您应该能够遍历范围以使用?page= 构建正确的链接。

    === 编辑 ===
    所以你的观点会是这样的:

    def blog(request):
        paginator = Paginator(Blog.objects.all(), 1)
    
        try:
            page = int(request.GET.get('page', '1'))
        except:
            page = 1
    
        try:
            blogs = paginator.page(page)
        except(EmptyPage, InvalidPage):
            blogs = paginator.page(1)
    
        # Get the index of the current page
        index = blogs.number - 1  # edited to something easier without index
        # This value is maximum index of your pages, so the last page - 1
        max_index = len(paginator.page_range)
        # You want a range of 7, so lets calculate where to slice the list
        start_index = index - 3 if index >= 3 else 0
        end_index = index + 3 if index <= max_index - 3 else max_index
        # Get our new page range. In the latest versions of Django page_range returns 
        # an iterator. Thus pass it to list, to make our slice possible again.
        page_range = list(paginator.page_range)[start_index:end_index]
    
        return render(request, 'blogs.html', {
            'blogs': blogs,
            'page_range': page_range,
        })
    

    所以现在我们必须编辑您的模板以接受我们的新页码列表:

    <div class="prev_next">
        {% if blogs.has_previous %}
            <a class="prev btn btn-info" href="?page={{blogs.previous_page_number}}">Prev</a>
        {% endif %}
        {% if blogs.has_next %}
            <a class="next btn btn-info" href="?page={{blogs.next_page_number}}">Next</a>
        {% endif %}
        <div class="pages">
            <ul>
            {% for pg in page_range %}
                {% if blogs.number == pg %}
                    <li><a href="?page={{pg}}" class="btn btn-default">{{pg}}</a></li>
                {% else %}
                    <li><a href="?page={{pg}}" class="btn">{{pg}}</a></li>
                {% endif %}
            {% endfor %}
            </ul>
        </div>
        <span class="clear_both"></span>
    </div>
    

    【讨论】:

    • 对不起,我没有得到你。能否请您详细说明一下。
    • @Robin,看看我的改动。
    • 例外:序列索引必须是整数,而不是 page_range 上的“切片” = paginator.page_range[start_index:end_index]
    • @RaymondSeger,这是因为 Django 改变了它的功能,在旧函数中 paginator.page_range 是一个列表,现在它返回一个迭代器。将更新我的答案。
    【解决方案4】:

    我发现最简单的方法是创建一个分页 sn-p,它只显示您想要的页面。

    就我而言,我不想要任何上一个或下一个链接。我只是想始终有一个指向第一页和最后一页的链接,然后有当前页面和当前页面两侧的两个页面。

    我的模板 sn-p(使用 django-tables2 中的变量 - 如果您直接使用 Django Paginator,变量的名称会略有不同)

    {% load django_tables2 %}
    {% load humanize %}
    {% load i18n %}
    
    {% if table.page %}
      {% with table.page.paginator.count as total %}
        {% with table.page.number as page_num %}
          {% with table.page.paginator.num_pages as num_pages %}
            {% block pagination %}
              <div class="row">
                <div class="col-md-12">    
                  {% if table.paginator.num_pages > 1 %}
                    <ul class="pagination pull-right">
                      {% for n in table.page.paginator.page_range %}
                        {% if table.page.number|add:'-3' == n %}
                          {# First page #}
                          <li><a href="{% querystring table.prefixed_page_field=1 %}">1</a></li>
                          {% if n != 1 %}
                            <li class="disabled"><a>&#8943;</a></li>
                          {% endif %}
                        {% elif table.page.number == n %}
                          {# Current page #}
                          <li class="active"><a href="#">{{ n }}</a></li>
                        {% elif table.page.number|add:'-3' < n and n < table.page.number|add:'3' %}
                          {# Pages around current page #}
                          <li><a href="{% querystring table.prefixed_page_field=n %}">{{ n }}</a></li>
                        {% elif table.page.number|add:'3' == n %}
                          {# Last page #}
                          {% if n != num_pages %}
                            <li class="disabled"><a>&#8943;</a></li>
                          {% endif %}
                          <li><a href="{% querystring table.prefixed_page_field=num_pages %}">{{ num_pages }}</a></li>
                        {% endif %}
                      {% endfor %}
                    </ul>
                  {% endif %}
                </div>
              </div>
            {% endblock pagination %}
          {% endwith %}
        {% endwith %}
      {% endwith %}
    {% endif %}
    

    我的分页在不同页面上的示例

    致谢:这是受到@Pavel1114's answer 的启发。

    【讨论】:

      【解决方案5】:

      Django 3.2 引入a new feature on the Paginator class:

      Paginator.get_elided_page_range(number, *, on_each_side=3, on_ends=2)
      

      使用on_each_sideon_ends的默认值,如果当前页面为10并且有50页,则页面范围为[1, 2, '…', 7, 8, 9, 10, 11, 12, 13, '…', 49, 50]

      【讨论】:

      【解决方案6】:

      您还可以扩展 Paginator 类。

      class BootstrapPaginator(Paginator):
          def __init__(self, *args, **kwargs):
              """        
              :param wing_pages: How many pages will be shown before and after current page.
              """
              self.wing_pages = kwargs.pop('wing_pages', 3)
              super(BootstrapPaginator, self).__init__(*args, **kwargs)
      
          def _get_page(self, *args, **kwargs):
              self.page = super(BootstrapPaginator, self)._get_page(*args, **kwargs)
              return self.page
      
          @property
          def page_range(self):
              return range(max(self.page.number - self.wing_pages, 1),
                           min(self.page.number + self.wing_pages + 1, self.num_pages + 1))
      

      然后在模板中:

      {% for num in action_list.paginator.page_range %}
          {% if action_list.number == num %}
               <li class="active"><a href="?page={{ num }}">{{ num }}</a></li>
          {% else %}
               <li><a href="?page={{ num }}">{{ num }}</a></li>
          {% endif %}
      {% endfor %}
      

      现在page_range 将只包含 7 个项目。 wing_pages + 当前页面 + wing_pagescustom django paginator for bootstrap

      【讨论】:

        【解决方案7】:

        灵感来自 @Pavel1114@Inti。删除了开头和结尾的箭头,因为它们不是那么有用。增加首页和末页,访问更快捷。

        <ul>
          <li class="grp-results">
              <span>{{paginator.count}} total</span>
          </li>
          {% if data.number|add:'-4' > 1 %}
            <li><a href="?page=1">1</a></li>
            <li><a href="?page={{ data.number|add:'-5' }}">&hellip;</a></li>
          {% endif %}
          {% for i in data.paginator.page_range %}
            {% if data.number == i %}
                <li class="active"><span>{{ i }}</span></li>
            {% elif i > data.number|add:'-3' and i < data.number|add:'3' %}
                <li><a href="?page={{ i }}">{{ i }}</a></li>
              {% endif %}
          {% endfor %}
          {% if data.paginator.num_pages > data.number|add:'4' %}
            <li><a href="?page={{ data.number|add:'5' }}">&hellip;</a></li>
            <li><a href="?page={{ data.paginator.count }}">{{ data.paginator.count }}</a></li>
          {% endif %}
        </ul>
        

        【讨论】:

          【解决方案8】:

          您可以使用以下代码。

               <nav aria-label="Page navigation example">
                  <ul class="pagination justify-content-center">
          
                      <li class="page-item {% if not page_obj.has_previous %} disabled {% endif %}">
                          <a class="page-link" href="?page=1" tabindex="-1">FIRST</a>
                      </li>
                      <li class="page-item {% if not page_obj.has_previous %} disabled {% endif %}">
                          <a class="page-link" href="{% if page_obj.has_previous %}?page={{ page_obj.previous_page_number }}{% endif %} " tabindex="-1">Previous</a>
                      </li>
          
                      {% if page_obj.number|add:'-4' > 1 %}
                          <li class="page-item disabled"><a class="page-link" href="?page={{ page_obj.number|add:'-5' }}">&hellip;</a></li>
                      {% endif %}
          
                      {% for i in page_obj.paginator.page_range %}
                          {% if page_obj.number == i %}
                              <li class="active page-item disabled"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                          {% elif i > page_obj.number|add:'-5' and i < page_obj.number|add:'5' %}
                              <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                          {% endif %}
                      {% endfor %}
          
                      {% if page_obj.paginator.num_pages > page_obj.number|add:'4' %}
                          <li class="page-item disabled"><a class="page-link" href="?page={{ page_obj.number|add:'5' }}">&hellip;</a></li>
                      {% endif %}
          
                      <li class="page-item {% if not page_obj.has_next %} disabled {% endif %}">
                          <a class="page-link" href="{% if page_obj.has_next %} ?page={{ page_obj.next_page_number }} {% endif %}">Next</a>
                      </li>
                      <li class="page-item {% if not page_obj.has_next %} disabled {% endif %}">
                          <a class="page-link" href="{% if page_obj.has_next %} ?page={{ page_obj.paginator.num_pages }}  {% endif %}">LAST</a>
                      </li>
                  </ul>
              </nav>  
          

          【讨论】:

          • 根据当前页面,显示页码的链接数不固定。如果当前页面为 1:显示 5 个链接,如果当前页面为 5 或更多,则显示 9 个链接。如何显示相同数量的链接?
          【解决方案9】:

          我只在带有表达式的模板上这样做:

          {% if is_paginated %}
              <div class="text-center">
                  <ul class="pagination pagination-sm">
                      {% if page_obj.number >= 5 %}
                      <li><a href="?page=1">1</a></li>
                      <li><span>...</span></li>
                      {% elif page_obj.number == 4 %}
                      <li><a href="?page=1">1</a></li>
                      {% endif %}
                      {% if page_obj.number|add:"-2" >= 1  %}
                      <li><a href="?page={{ page_obj.number|add:"-2" }}">{{ page_obj.number|add:"-2" }}</a></li>
                      {% endif %}
                      {% if page_obj.number|add:"-1" >= 1  %}
                      <li><a href="?page={{ page_obj.number|add:"-1" }}">{{ page_obj.number|add:"-1" }}</a></li>
                      {% endif %}
                      <li class="active"><a href="?page={{ page_obj.number }}">{{ page_obj.number }}</a></li>
                      {% if page_obj.number|add:"1" <= paginator.num_pages  %}
                      <li><a href="?page={{ page_obj.number|add:"1" }}">{{ page_obj.number|add:"1" }}</a></li>
                      {% endif %}
                      {% if page_obj.number|add:"2" <= paginator.num_pages %}
                      <li><a href="?page={{ page_obj.number|add:"2" }}">{{ page_obj.number|add:"2" }}</a></li>
                      {% endif %}
                      {% if page_obj.number|add:"2" <= paginator.num_pages|add:"-2" %}
                      <li><span>...</span></li>
                      <li><a href="?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a></li>
                      {% elif page_obj.number|add:"1" <= paginator.num_pages|add:"-2" %}
                      <li><a href="?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a></li>
                      {% endif %}
                  </ul>
              </div>
          {% endif %}
          

          我知道 django 就像“不要再写你的代码”,但我发现这对我来说更容易理解。希望我有所帮助。

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签