Display only some of the page numbers by django pagination

前端 未结 8 1212
盖世英雄少女心
盖世英雄少女心 2020-12-07 10:34

I am using the django paginator in the template. Its working ok, but not good when there\'s large numbers of pages.

views.py:

def blog(request):
             


        
相关标签:
8条回答
  • 2020-12-07 11:01

    You can use the following code.

         <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>  
    

    0 讨论(0)
  • 2020-12-07 11:08

    I found the simplest thing to do was to create a pagination snippet that just shows the pages you want it to.

    In my case I didn't want any previous or next links. I just wanted to always have a link to the first and last pages and then have the current page and the two pages either side of the current page.

    My template snippet (uses variables from django-tables2 - variables will have slightly different names if you're using a Django Paginator directly)

    {% 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 %}
    

    Examples of what my pagination looks like at different pages

    Credit: this was inspired by @Pavel1114's answer.

    0 讨论(0)
  • 2020-12-07 11:11

    Another shorter solution with template is compare current forloop.counter with certain range.

    with bootstrap I use this template

    <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>
    

    0 讨论(0)
  • 2020-12-07 11:12

    First of all I would change the following:

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

    But you could pass a range within your context.

    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]
    

    Now you should be able to loop over the range to construct the right links with ?page=.

    === Edit ===
    So your view would be something like this:

    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,
        })
    

    So now we have to edit your template to accept our new list of page numbers:

    <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>
    
    0 讨论(0)
  • 2020-12-07 11:18

    You could also extend Paginator class.

    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))
    

    Then in template:

    {% 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 %}
    

    Now page_range will only consist of 7 items. wing_pages + current page + wing_pagescustom django paginator for bootstrap

    0 讨论(0)
  • 2020-12-07 11:20

    Inspired by @Pavel1114 and @Inti. Removed the arrow at the beginning and at the end as they are not that useful. Added The first page and last page for faster accessing.

    <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>
    

    0 讨论(0)
提交回复
热议问题