1. 程式人生 > 其它 >Django架構之自定義分頁器

Django架構之自定義分頁器

Django框架自定義分頁器

自定義分頁器

針對上一小節批量插入的資料,我們在前端展示的時候發現一個很嚴重的問題,一頁展示了所有的資料,資料量太大,檢視不方便

針對資料量大但又需要全部展示給使用者觀看的情況下,我們統一做法都是做分頁處理

分頁推導

首先我們需要明確的時候,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
"""

內建方法之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 %}

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

自定義分頁器封裝程式碼

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