2015-06-16 14 views
12

Używam paginatora django w szablonie. Działa dobrze, ale nie jest dobre, gdy jest duża liczba stron.Wyświetl tylko niektóre numery stron według paginacji 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 
     }) 

fragment szablonu:

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

Teraz wygląda to tak:

enter image description here

Co mam zrobić, aby wyświetlić tylko 7 numery stron i nie wszystkie z nich, począwszy od bieżącego numeru strony, na przykład:

Prev 1 (2) 3 4 5 Next 

Mam nadzieję, że było jasne, jeśli nie, proszę zapytać. Twoja pomoc i wskazówki będą bardzo cenne. Dziękuję Ci.

Odpowiedz

17

Przede wszystkim chciałbym zmienić następujące:

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

ale można przejść szereg w swoim kontekście.

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] 

Teraz powinieneś być w stanie pętli w całym zakresie skonstruować odpowiednie linki z ?page=.

=== Edit ===
Więc twój widok będzie coś takiego:

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

Więc teraz musimy edytować szablon, aby zaakceptować naszą nową listę numerów stron:

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

przykro mi, nie po ciebie. Czy mógłbyś rozwinąć nieco więcej. – Robin

+0

@Robin, zobacz moje zmiany. – Blackeagle52

+0

Świetnie! Zadziałało! Dziękuję Ci. – Robin

1

Można również rozszerzyć klasę 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)) 

Następnie w szablonie:

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

Teraz page_range będzie składać się tylko z 7 produktów. wing_pages + bieżąca strona + wing_pagescustom django paginator for bootstrap

0

Zrobiłem to tylko na szablonach wyrażeń:

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

wiem Django jest jak „dont napisać ponownie kod”, ale uważam, że to mi łatwiej zrozumieć teraz . Mam nadzieję, że pomogłem.

12

Innym krótszym rozwiązaniem z szablonem jest porównanie aktualnego forloop.counter z pewnym zakresem.

z bootstrap Używam tego szablonu

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

screenshot

+0

Podobała mi się ta odpowiedź najlepiej, znacznie krócej i łatwiej zrozumieć \ – ColinMasters

1

znalazłem najprostszym rozwiązaniem było stworzenie fragment paginacji że tylko pokazuje strony, które chcemy.

W moim przypadku nie chciałem żadnych poprzednich ani następnych linków. Chciałem zawsze mieć link do pierwszej i ostatniej strony, a następnie mieć bieżącą stronę i dwie strony po obu stronach bieżącej strony.

Mój szablon fragment (używa zmienne z Django tables2 - zmienne będą miały nieco inne nazwy, jeśli używasz Django Paginator bezpośrednio)

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

przykłady tego, co mój paginacja wygląda na różnych stronach

1

2

3

4

5

6

kredytowe: to był inspirowany przez użytkownika @ Pavel1114 odpowiedź

8

Zamierzam rzucić to w wpadłem na niego, ponieważ pozwala wiesz, że istnieją. więcej stron po obu stronach.

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

A wygląda to tak:

Paging with elipses

Powiązane problemy