[Django高階之批量插入資料、分頁器元件]

劉較瘦丫發表於2021-05-29

[Django高階之批量插入資料、分頁器元件]

批量插入資料

模板層models.py

from django.db import models

class Books(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish = models.CharField(max_length=32)

建表別忘了執行資料庫遷移命令哦

python3 manage.py makemigrations

python3 manage.py migrate

路由層urls.py

urlpatterns = [
    url(r'^books_page/', views.books_page), 
]

檢視層views.py

# 往Book表裡批量插入資料

def books_page(request):
   # 第一種方案,每迴圈一次,操作一下資料庫,效能低(相當於進行了1000次的資料庫連結)
    # for i in range(1000):
    #     book=models.Books.objects.create(name='圖書%s'%i,price=i+10,publish='東京出版社')
    #
--------------------------------------------------------------------------------------    
   # 第二種方案,批量插入
    book_list=[]  # 例項化物件放到列表裡
    for i in range(1000):
        book=models.Books(name='圖書%s'%i,price=i+10,publish='東京出版社')
        book_list.append(book)
    # bulk_create一次性插入,batch_size分批往裡面插
    models.Books.objects.bulk_create(book_list,batch_size=100)  # batch_size 指定一批數量

    return HttpResponse('ok')

# 當你想要批量插入資料的時候,使用ORM提供的 bulk_create 能夠大大的減少操作時間

自定義分頁器

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

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

分頁推導

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

img

資料總頁面獲取

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

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

答案:10條

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

答案:11條

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

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

img

內建方法之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框架拷貝程式碼即可
img

終極大法

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

自定義分頁器封裝程式碼

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>

img

相關文章