在 Django 中实现分页
2022-11-13 本文已影响0人
Svon_Book
借助 Django 自带的 Paginator工具,实现类似B站的分页效果
伪码实现
# views.py
def view_func(request):
接收 page 页参数
result = Paginate(待分页对象, page, 每页元素数量)
return render(...,{'result': result})
class Pagination():
验证 page 是否合理
if 空页面 or 非法参数:
raise Http404
def items(self):
返回分页后的对象
def html_string(self):
返回 html 文本,便于前端渲染
<!--index.html-->
{% for r in result.items %}
输入分页元素
{% endfor %}
{% result.html_string %}
1. page 参数验证
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
class Paginate(object):
def __init__(self, queryset, page, per_page=10):
"""
:param queryset: 需要分页的对象集合
:param page: 获取指定页数的对象集合,例如2/20
:param per_page: 每页对象元素数量,默认10
"""
self.django_paginator_obj = Paginator(queryset, per_page)
try:
self.current_page = self.django_paginator_obj.validate_number(page)
except EmptyPage:
raise Http404('该页无内容')
except PageNotAnInteger:
raise Http404('页码格式无效')
self.current_page_items = self.django_paginator_obj.get_page(self.current_page)
2. 返回分页后的对象
class Paginate(object):
...
def items(self):
"""
按给定的 page 返回分页后的对象
:return: QuerySet
"""
return self.current_page_items.object_list
3. 返回HTML 文本标记
3.1 返回后的 HTML 标记格式如下
借助 Bootstrap 样式实现:
image.png
3.2 三种页数情况的处理方法
image.png3.3 关键代码
class Paginate(object):
...
def page_html_string(self):
"""
:return: html element
"""
start = end = 0
# 处理总页不过5的情况
if self.django_paginator_obj.num_pages <= 5:
start = 1
end = self.django_paginator_obj.num_pages
else:
# 处理 “初始页” 极值的情况
if self.current_page - 2 <= 1:
start = 1
end = 5
# 处理 “最后页” 极值的情况
elif self.current_page + 2 >= self.django_paginator_obj.num_pages:
start = self.django_paginator_obj.num_pages - 5 + 1
end = self.django_paginator_obj.num_pages
else:
# 处理常规情况下5个分页连接的的起、止页码
start = self.current_page - 2
end = self.current_page + 2
page_string = "<ul class=\"pagination\">"
# 处理上一页
if self.current_page_items.has_previous():
page_string += "<li><a href=\"?page={}\"><span>«</span></a></li>".format(
self.current_page - 1)
else:
page_string += "<li class=\"disabled\"><a href=\"#\"><span>«</span></a></li>"
# “首页”页码与 “...” 字样
if self.current_page - 2 > 1:
page_string += "<li class=\"active\"><a href=\"?page=1\">1</a></li>"
page_string += "<li><a>...</a></li>"
# 中间区域5个页码
for i in range(start, end + 1):
if i == self.current_page:
page_string += "<li class=\"active\"><a href=\"?page={0}\">{0}</a></li>".format(i)
else:
page_string += "<li><a href=\"?page={0}\">{0}</a></li>".format(i)
# “尾页”页码与 “...” 字样
if self.current_page + 2 < self.django_paginator_obj.num_pages:
page_string += "<li><a>...</a></li>"
page_string += "<li><a href=\"?page={0}\">{0}</a></li>".format(self.django_paginator_obj.num_pages)
if self.current_page_items.has_next():
page_string += "<li><a href=\"?page={}\"><span>»</span></a></li>".format(
self.current_page + 1)
else:
page_string += "<li class=\"disabled\"><a href=\"#\"><span>»</span></a></li>"
page_string += "</ul>"
return mark_safe(page_string)