在 Django 中实现分页

借助 Django 自带的 Paginator工具,实现类似B站的分页效果

image.png

伪码实现

# 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 文本,便于前端渲染

{% 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.png

3.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 = "
    " # 处理上一页 if self.current_page_items.has_previous(): page_string += "
  • «
  • ".format( self.current_page - 1) else: page_string += "
  • «
  • " # “首页”页码与 “...” 字样 if self.current_page - 2 > 1: page_string += "
  • 1
  • " page_string += "
  • ...
  • " # 中间区域5个页码 for i in range(start, end + 1): if i == self.current_page: page_string += "
  • {0}
  • ".format(i) else: page_string += "
  • {0}
  • ".format(i) # “尾页”页码与 “...” 字样 if self.current_page + 2 < self.django_paginator_obj.num_pages: page_string += "
  • ...
  • " page_string += "
  • {0}
  • ".format(self.django_paginator_obj.num_pages) if self.current_page_items.has_next(): page_string += "
  • »
  • ".format( self.current_page + 1) else: page_string += "
  • »
  • " page_string += "
" return mark_safe(page_string)

最终效果

image.png

你可能感兴趣的:(在 Django 中实现分页)