34 custom pager

Posted by kingconnections on Thu, 02 Dec 2021 21:35:27 +0100

Custom pager

For the batch data inserted in the previous section, we found a very serious problem in the front-end display. All the data is displayed on one page. The amount of data is too large and it is inconvenient to view

In the case of a large amount of data that needs to be displayed to users, our unified practice is to do paging processing

Paging derivation

First of all, when we need to be clear, the get request can also carry parameters, so we can carry a parameter to tell the back-end what page we want to see when we send the view data to the back-end

Secondly, we also need to know that the queryset object supports index retrieval and slicing, but does not support negative indexes

Next, we can deduce our custom pager steps

current_page = request.GET.get("page",1)  # Get the page number that the user wants to access. If there is no default page, the first page will be displayed
try:  # Since the front-end data received by the back-end is of string type, we do type conversion and exception capture here
  current_page = int(current_page)
except Exception as e:
  current_page = 1
# You also need to define how many pieces of data the page displays
per_page_num = 10  # Display 10 pieces of data on one page

# The total data needs to be sliced, and the start position and end position of the slice need to be determined
start_page = ? 
end_page = ?
"""
The following needs to be studied current_page,per_page_num,start_page,end_page Data relationship between the four parameters
per_page_num = 10
current_page                start_page                  end_page
    1                           0                           10
    2                           10                          20
    3                           20                          30  
    4                           30                          40

per_page_num = 5
current_page                start_page                  end_page
    1                           0                           5
    2                           5                           10
    3                           10                          15  
    4                           15                          20
 You can clearly see the law
start_page = (current_page - 1) * per_page_num
end_page =  current_page* per_page_num
"""

Total data page acquisition

When I ask you the following questions, your heart must despise. If you don't believe it, please listen to the questions

Question 1:There are 100 pieces of data in total, and 10 pieces are displayed on each page. How many pages are needed in total?

answer:10 strip

Question 2:There are 101 pieces of data in total, and 10 pieces are displayed on each page. How many pages are needed in total?

answer:11 strip

Question 3:How to calculate how many pieces are needed through code?

answer:Fuck your sister, no!!!

Built in method divmod

>>> divmod(100,10)
(10, 0)  # 10 page
>>> divmod(101,10)
(10, 1)  # 11 page
>>> divmod(99,10)
(9, 9)  # 10 page
# As long as the remainder is not 0, you need to add one to the first number

We can judge whether the second number of Yuanzu is 0, so as to determine how many pages are needed to display the data

book_queryset = models.Book.objects.all()
all_count = book_queryset.count()  # Total number of data
all_pager, more = divmod(all_count, per_page_num)
if more:  # If there is a remainder, add one to the total number of pages
  all_pager += 1

So far, we have roughly understood the general functions and ideas of the pager

Finally, we just need to use start_page and end_page slice the total data and then transfer it to the front-end page to realize paging display

book_list = models.Book.objects.all()[start_page:end_page]
return render(request,'booklist.html',locals())

The next step is the coding of the front-end page

{% for book in book_list %}
    <p>{{ book.title }}</p>
{% endfor %}

Now we have implemented the simplest paging, but there is no button on the front end to let users click. We need to see the page, so we need to render the code related to the pager. Here, we don't need to copy the code directly to the bootstrap framework

Ultimate Dharma

The above is the basic idea of the development process of custom pager. We don't need to master the code writing, we just need to master the basic usage

Custom pager encapsulation code

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
        """
        Encapsulate paging related data
        :param current_page: Current page
        :param all_count:    Total number of data in the database
        :param per_page_num: Number of data pieces displayed per page
        :param pager_count:  Maximum number of page numbers displayed
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # Total page number
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # If total page number < 11 Number:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # Total page number  > 11
        else:
            # Current page if<=Up to 11 are displayed on the page/2 Page number
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # The current page is greater than 5
            else:
                # Page number last
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # Add previous nav and ul label
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">home page</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#"> previous page</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">previous page</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#"> next page</a></li>'
        else:
            next_page = '<li><a href="?page=%s">next page</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">Last page</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # Add label to tail
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)

Custom pager usage

back-end

def get_book(request):
   book_list = models.Book.objects.all()
   current_page = request.GET.get("page",1)
   all_count = book_list.count()
   page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
   page_queryset = book_list[page_obj.start:page_obj.end]
   return render(request,'booklist.html',locals())

front end

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {% for book in page_queryset %}
            <p>{{ book.title }}</p>
            {% endfor %}
            {{ page_obj.page_html|safe }}
        </div>
    </div>
</div>