1. 程式人生 > >自定義分頁器

自定義分頁器

分頁推導

首先我們需要明確的時候,get請求也是可以攜帶引數的,所以我們在朝後端傳送檢視資料的同時可以攜帶一個引數告訴後端我們想看第幾頁的資料

其次我們還需要知道一個點,queryset物件是支援索引取值和切片操作的,但是不支援負數索引情況

接下來我們就可以推導我們的自定義分頁器步驟了

current_page = request.GET.get("page",1)  # 獲取使用者想訪問的頁碼  如果沒有 預設展示第一頁
try:  # 由於後端接受到的前端資料是字串型別所以我們這裡做型別轉換處理加異常捕獲
  current_page = int(current_page)
except Exception as e:
  current_page = 1
# 還需要定義頁面到底展示幾條資料
per_page_num = 10  # 一頁展示10條資料

# 需要對總資料進行切片操作 需要確定切片起始位置和終止位置
start_page = ? 
end_page = ?
"""
下面需要研究current_page、per_page_num、start_page、end_page四個引數之間的資料關係
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
可以很明顯的看出規律
start_page = (current_page - 1) * per_page_num
end_page =  current_page* per_page_num
"""

資料總頁面獲取

當我問你下面幾個問題的時候,你的內心肯定是鄙視的,不信的話那就請聽題

問題1:總資料有100條,每頁展示10條,總共需要幾頁?

答案:10條

問題2:總資料有101條,每頁展示10條,總共需要幾頁?

答案:11條

問題3:如何通過程式碼算出到底需要多少條?

答案:去你妹的,不會!!!

內建方法之divmod

>>> divmod(100,10)
(10, 0)  # 10頁
>>> divmod(101,10)
(10, 1)  # 11頁
>>> divmod(99,10)
(9, 9)  # 10頁
# 餘數只要不是0就需要在第一個數字上加一

我們可以判斷元祖的第二個數字是否為0從而確定到底需要多少頁來展示資料

book_queryset = models.Book.objects.all()
all_count = book_queryset.count()  # 資料總條數
all_pager, more = divmod(all_count, per_page_num)
if more:  # 有餘數則總頁數加一
  all_pager += 1

至此分頁器大致的功能及思路我們就已經大致清楚了

最後我們只需要利用start_page和end_page對總資料進行切片取值再傳入前端頁面就能夠實現分頁展示

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

接下來就是前端頁面的程式碼編寫了

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

現在我們實現了最簡單的分頁,但是前端沒有按鈕去讓使用者點選需要看第幾頁,所以我們需要渲染分頁器相關程式碼,這裡我們不做要求直接去bootstrap框架拷貝程式碼即可

終極大法

上面是自定義分頁器開發流程的基本思路,我們不需要掌握程式碼的編寫,只需要掌握基本用法即可

自定義分頁器封裝程式碼

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
        """
        封裝分頁相關資料
        :param current_page: 當前頁
        :param all_count:    資料庫中的資料總條數
        :param per_page_num: 每頁顯示的資料條數
        :param pager_count:  最多顯示的頁碼個數
        """
        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

        # 總頁碼
        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):
        # 如果總頁碼 < 11個:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 總頁碼  > 11
        else:
            # 當前頁如果<=頁面上最多顯示11/2個頁碼
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 當前頁大於5
            else:
                # 頁碼翻到最後
                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 = []
        # 新增前面的nav和ul標籤
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首頁</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一頁</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一頁</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="#">下一頁</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一頁</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾頁</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部新增標籤
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)

自定義分頁器的使用

後端

 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)
   #針對真實的queryset資料進行切片操作
   page_queryset = book_list[page_obj.start:page_obj.end]
   return render(request,'booklist.html',locals())

前端

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