瀏覽器存取一個django路由 立刻建立10萬條資料並展示到前端頁面
def index(request):
# 插入10000條資料
for i in range(10000):
models.Book.objects.create(title='第%s本書' % i)
book_queryset = models.Book.objects.all()
def index(request):
# 插入10000條資料
# for i in range(10000):
# models.Book.objects.create(title='第%s本書' % i)
book_list = []
for i in range(10000):
book_obj = models.Book(title=f'第{i}本書')
book_list.append(book_obj)
# [models.Book(title=f'第{i}本書') for i in range(10000)] # 可以使用列表生成式
models.Book.objects.bulk_create(book_list) # 批次建立
# models.Book.objects.bulk_update() # 批次建立
book_queryset = models.Book.objects.all() # 查詢資料
return render(request, 'bookList.html', locals())
涉及到大批次資料的建立 直接使用create可能會造成資料庫崩潰
批次資料建立>>>:bulk_create()
批次資料修改>>>:bulk_update()
前端頁面展示資料
{% for book_obj in book_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
1.針對上一小節批次插入的資料,我們在前端展示的時候發現一個很嚴重的問題,一頁展示了索引的資料,資料量太大,檢視不方便
2.針對資料量大但又需要全部展示給使用者觀看的情況下,我們統一做法都是做分頁處理。很多網站都做了這樣的操作
當資料量比較大的時候 頁面展示應該考慮分頁
1.QuerySet切片操作
2.分頁樣式新增
3.頁碼展示
如何根據總資料和每頁展示的資料得出總頁碼
divmod()
4.如何渲染出所有的頁碼標籤
前端模板語法不支援range 但是後端支援 我們可以在後端建立好html標籤然後傳遞給html頁面使用
5.如何限制住展示的頁面標籤個數
頁碼推薦使用奇數位(對稱美) 利用當前頁前後固定位數來限制
6.首尾頁碼展示範圍問題
"""
上述是分頁器元件的推導流程 我們無需真正編寫
django自帶一個分頁器元件 但是不太好用 我們自己也寫了一個
"""
def ab_pl(request):
book_data = models.Book.objects.all()
# 計算總共資料條數
all_count = book_data.count()
# 2.自定義每頁展示的資料條數
per_page_num = 10
all_page_num, more = divmod(all_count, per_page_num)
if more:
all_page_num += 1
# 後端生成頁碼標籤
html_page = ''
for i in range(1, all_page_num):
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
# 1.獲取前端想要展示的頁碼
current_page = request.GET.get('page', 1) # 獲取使用者展示的page頁 如果麼有則預設展示1
try:
current_page = int(current_page)
except TypeError:
current_page = 1
# 3.定義出切片起始位置
start_num = (current_page - 1) * per_page_num
# 4.定義出切片終止位置
end_num = current_page * per_page_num
book_query = book_data[start_num:end_num] # QuerySet [資料物件 資料物件]
return render(request, 'bookList.html', locals())
動態計算/解析出 起始位置 與 終止位置
# 每頁展示10條
per_page_num = 10
頁 起始位置 終止位置
current_page start_page end_page
1 0 10
2 10 20
3 20 30
4 30 40
# 每頁展示5條
per_page_num = 5
頁 起始位置 終止位置
current_page start_page end_page
1 0 5
2 5 10
3 10 15
4 15 20
計算出 起始位置 與 終止位置
0 = (1 - 1) * 5
start_page = (current_page - 1) * per_page_num
5 = 1 * 5
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就需要在第一個數位上加一
book_data = models.Book.objects.all()
# 計算總共資料條數
all_count = book_data.count()
# 2.自定義每頁展示的資料條數
per_page_num = 10
all_page_num, more = divmod(all_count, per_page_num)
# 我們可以判斷元祖的第二個數位是否為0從而確定到底需要多少頁來展示資料
if more:
all_page_num += 1
# 後端生成頁碼標籤
html_page = ''
for i in range(1, all_page_num):
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
book_query = book_data[start_num:end_num] # QuerySet [資料物件 資料物件]
return render(request, 'bookList.html', locals())
後端程式碼
def index(request):
book_data = models.Book.objects.all()
# 計算總共資料條數
all_count = book_data.count()
# 2.自定義每頁展示的資料條數
per_page_num = 10
all_page_num, more = divmod(all_count, per_page_num)
if more:
all_page_num += 1
# 後端生成頁碼標籤
html_page = ''
for i in range(1, all_page_num):
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
# 1.獲取前端想要展示的頁碼
current_page = request.GET.get('page', 1) # 獲取使用者展示的page頁 如果麼有則預設展示1
try:
current_page = int(current_page)
except TypeError:
current_page = 1
# 3.定義出切片起始位置
start_num = (current_page - 1) * per_page_num
# 4.定義出切片終止位置
end_num = current_page * per_page_num
book_query = book_data[start_num:end_num] # QuerySet [資料物件 資料物件]
return render(request, 'bookList.html', locals())
前端頁面
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book_obj in book_query %}
<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
<nav aria-label="Page navigation " class="text-center">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{{ html_page | safe }}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
頁碼推薦使用奇數位(對稱美) 利用當前頁前後固定位數來限制
def index(request):
book_data = models.Book.objects.all()
# 計算總共資料條數
all_count = book_data.count()
# 2.自定義每頁展示的資料條數
per_page_num = 10
all_page_num, more = divmod(all_count, per_page_num)
if more:
all_page_num += 1
# 1.獲取前端想要展示的頁碼
current_page = request.GET.get('page', 1) # 獲取使用者展示的page頁 如果麼有則預設展示1
try:
current_page = int(current_page)
except TypeError:
current_page = 1
# 後端生成頁碼標籤
html_page = ''
xxx = current_page
# 一旦頁碼小於6的時候就叫他等於6,否則不做處理的話就會頁面變為負數,出現報錯
if current_page < 6:
xxx = 6
for i in range(xxx - 5, xxx + 6):
if current_page == i:
# 如果當前頁面是展示的頁面就新增一個active
html_page += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
else:
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
# 3.定義出切片起始位置
start_num = (current_page - 1) * per_page_num
# 4.定義出切片終止位置
end_num = current_page * per_page_num
book_query = book_data[start_num:end_num] # QuerySet [資料物件 資料物件]
return render(request, 'bookList.html', locals())
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for book_obj in book_query %}
<p class="text-center">{{ book_obj.title }}</p>
{% endfor %}
<nav aria-label="Page navigation " class="text-center">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{{ html_page |safe}}
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
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: 最多顯示的頁碼個數
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
獲取資料用page_data而不再使用原始的queryset
獲取前端分頁樣式用page_obj.page_html
"""
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)
1.當我們需要使用到非django內建的第三方功能或者元件程式碼的時候
我們一般情況下會建立一個名為utils資料夾 在該資料夾內對模組進行功能性劃分
utils可以在每個應用下建立 具體結合實際情況
2.我們到了後期封裝程式碼的時候 不再侷限於函數
還是儘量朝物件導向去封裝
3.我們自定義的分頁器是基於bootstrap樣式來的 所以你需要提前匯入bootstrap
bootstrap 版本 v3
jQuery 版本 v3
"""
utils可以建在專案下,也可以建在應用下!
"""
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=10, 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)
後端
# 匯入utils檔案
from utils.mypage import Pagination
def ab_pl(request):
# 獲取頁面展示多少資料
book_queryset = models.Book.objects.all()
# 當前頁
current_page = request.GET.get('page', 1)
# 總條數
all_count = book_queryset.count()
# 1.傳值生成物件
page_obj = Pagination(current_page=current_page, all_count=all_count)
# 2.直接對總資料進行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end] # 計算出起始位置與終止位置
# 3.將page_queryset傳遞到頁面 替換之前的book_queryset
return render(request,'ab_pl.html',locals())
前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--bootstrap引入 CSS CDN-->
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<!--jQuery引入 CDN-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!--Bootstrap引入 Js CDN-->
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#迴圈資料#}
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
{# 利用自定義分頁器直接顯示分頁器樣式 #}
{{ page_obj.page_html|safe }}
</body>
</html>