Django扩展 分页组件

我们在展示信息过程中,如果信息量过多,会给人非常的不友好,这个时候需要通过分页使得界面更简洁友好

Django 基于GET请求的分页功能

假设 每一个 显示十条数据 可得到以下公式

页码起始结束
1 0 10
2 10 20
3 20 30
... ... ...
... (page-1)*5 page*10

我们用代码实现一下吧

page_num = int(request.GET.get("page")) # 获取页码数

per_page_num = 10 # 每页显示条数

# 通过条件对查询到的数据进行切片处理
customers_obj = models.Customer.objects.all()[
    (page_num-1)*per_page_num:page_num*per_page_num
]

我们需要在前端生成分页按钮

分析

  • 需要获取每页显示的数量
  • 需要获取页码生成的数量
  • 前端进行循环生成

页码生成的数量 = 数据总数 / 每页显示的数量

def customers(request):

    page_num = int(request.GET.get("page"))
    per_page_num = 10  # 每页显示条数

    customers_count = models.Customer.objects.all().count() # 获取总数据数量
    shanum, yunum = divmod(customers_count, per_page_num) # 计算商数和余数
    
    # 生成要展示的页码数
    if yunum:
        page_num_count = shanum + 1
    else:
        page_num_count = shanum

    # 根据每页显示的条数对查出来的数据进行切割
    customers_obj = models.Customer.objects.all()[
        (page_num-1)*per_page_num:page_num*per_page_num
    ]

    return render(
        request,
        "saleshtml\\customers.html",
        {
            "customers_obj": customers_obj,
            "page_num_count": range(1, page_num_count+1) # 展示页码没有第一页
        }
    )
<nav aria-label="Page navigation">
    <ul class="pagination">
      <li>
        <a href="#" aria-label="Previous">
          <span aria-hidden="true">&laquo;</span>
        </a>
      </li>
      {% for i in page_num_range %}
        <li><a href="/customers/?page={{i}}">{{i}}</a></li>
      {% endfor %}
      <li>
        <a href="#" aria-label="Next">
          <span aria-hidden="true">&raquo;</span>
        </a>
      </li>
    </ul>
  </nav>

  • 生成页面样式不友好 如果上百页 就一堆页码条

对页码生成逻辑进行改进

所在页码字段1字段2字段3字段4字段5
3 1 2 3 4 5
4 2 3 4 5 6
5 3 4 5 6 7
6 4 5 6 7 8

分析

  • 字段三两边的数量: 分页按钮的条数 整除 2
  • 分页按钮起始: 当前页码 - 字段三两边的数量
  • 分页按钮结束: 当前页码 + 字段三两边的数量
def customers(request):
    try:
        page_num = int(request.GET.get("page"))
    except Exception:
        page_num = 1

    per_page_num = 10  # 每页显示条数

    customers_count = models.Customer.objects.all().count() # 获取总数据数量
    shanum, yunum = divmod(customers_count, per_page_num) # 计算商数和余数

    # 生成要展示的页码数
    if yunum:
        page_num_count = shanum + 1
    else:
        page_num_count = shanum

    # 如果页码数小于等于零 或者大于总页码数 让他不出问题
    if page_num <= 0:
        page_num = 1
    elif page_num > page_num_count:
        page_num = page_num_count


    # 根据每页显示的条数对查出来的数据进行切割
    customers_obj = models.Customer.objects.all()[
        (page_num-1)*per_page_num:page_num*per_page_num
    ]

    page_num_show = 5 # 分页按钮生成的数量
    half_show = page_num_show//2 # 分页按钮中心两端的数量
    start_page_num = page_num - half_show # 开始位置
    end_page_num = page_num + half_show +1 # 结束位置

    page_num_range = range(start_page_num, end_page_num)
    return render(
        request,
        "saleshtml\\customers.html",
        {
            "customers_obj": customers_obj,
            "page_num_range": page_num_range,
        }
    )

问题:

解决:

  • 页码数由后台生成
start_page_num = page_num - half_show # 开始位置
end_page_num = page_num + half_show +1 # 结束位置
  • 解决问题
def customers(request):
    try:
        page_num = int(request.GET.get("page"))
    except Exception:
        page_num = 1

    per_page_num = 10  # 每页显示条数

    customers_count = models.Customer.objects.all().count() # 获取总数据数量
    shanum, yunum = divmod(customers_count, per_page_num) # 计算商数和余数

    # 生成要展示的页码数
    if yunum:
        page_num_count = shanum + 1
    else:
        page_num_count = shanum

    # 如果页码数小于等于零 或者大于总页码数 让他不出问题
    if page_num <= 0:
        page_num = 1
    elif page_num > page_num_count:
        page_num = page_num_count


    # 根据每页显示的条数对查出来的数据进行切割
    customers_obj = models.Customer.objects.all()[
        (page_num-1)*per_page_num:page_num*per_page_num
    ]

    page_num_show = 5 # 分页按钮生成的数量
    half_show = page_num_show//2 # 分页按钮中心两端的数量

    if page_num - half_show <= 0:
        start_page_num = 1
        end_page_num = page_num_show + 1
    elif page_num + half_show > page_num_count:
        start_page_num = page_num_count - page_num_show + 1
        end_page_num = page_num_count + 1
    else:
        start_page_num = page_num - half_show # 开始位置
        end_page_num = page_num + half_show +1 # 结束位置

    page_num_range = range(start_page_num, end_page_num)
    return render(
        request,
        "saleshtml\\customers.html",
        {
            "customers_obj": customers_obj,
            "page_num_range": page_num_range,
        }
    ) 

对分页功能进行封装

封装到后台

def customers(request):
    try:
        page_num = int(request.GET.get("page"))
    except Exception:
        page_num = 1

    per_page_num = 10  # 每页显示条数

    customers_count = models.Customer.objects.all().count() # 获取总数据数量
    shanum, yunum = divmod(customers_count, per_page_num) # 计算商数和余数

    # 生成要展示的页码数
    if yunum:
        page_num_count = shanum + 1
    else:
        page_num_count = shanum

    # 如果页码数小于等于零 或者大于总页码数 让他不出问题
    if page_num <= 0:
        page_num = 1
    elif page_num > page_num_count:
        page_num = page_num_count


    # 根据每页显示的条数对查出来的数据进行切割
    customers_obj = models.Customer.objects.all()[
        (page_num-1)*per_page_num:page_num*per_page_num
    ]

    page_num_show = 5 # 分页按钮生成的数量
    half_show = page_num_show//2 # 分页按钮中心两端的数量

    if page_num - half_show <= 0:
        start_page_num = 1
        end_page_num = page_num_show + 1
    elif page_num + half_show > page_num_count:
        start_page_num = page_num_count - page_num_show + 1
        end_page_num = page_num_count + 1
    else:
        start_page_num = page_num - half_show # 开始位置
        end_page_num = page_num + half_show +1 # 结束位置

    page_num_range = range(start_page_num, end_page_num)

    page_html = ''

    # 开头标签样式之类
    page_per_html = '''
        <nav aria-label="Page navigation">
        <ul class="pagination">'''
    page_html += page_per_html

    # 上一页
    if page_num > 1:
        per_page = f'''
            <li><a href="/customers/?page={page_num-1}" aria-label="Previous">
            <span aria-hidden="true">&laquo;</span></a></li>'''
        page_html += per_page

    # 循环添加按钮
    for page in page_num_range:
        page_num_html = f'''
            <li><a href="/customers/?page={page}">{page}</a></li>
        '''
        page_html += page_num_html

    # 下一页
    if page_num < page_num_count:
        next_page = f'''
        <li><a href="/customers/?page={page_num+1}" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
        </a></li>
        '''
        page_html += next_page

    # 标签样式收尾
    page_next_html = '''</ul></nav>'''
    page_html += page_next_html

    return render(
        request,
        "saleshtml\\customers.html",
        {"customers_obj": customers_obj, "page_html": page_html,})

 

<!--前端通过safe使字符串变成可用标签-->
{{ page_html|safe }} 

 

将分页功能封装成组件

# mark_safe 将后端生成的字符串标记为HTML 前端直接使用 就不用再 {{xxx|salf}}
from django.utils.safestring import mark_safe

class MyPageNation():
    def __init__(self, page_num, total_count, per_page_num, page_num_show, base_url):
        self.per_page_num = per_page_num  # 每页显示数据条数
        self.page_num_show = page_num_show  # 分页按钮生成的数量
        self.base_url = base_url  # 分页组件中的URL
        self.total_count = total_count # 数据的总量
        try:
            page_num = int(page_num)
        except Exception:
            page_num = 1
        self.page_num = page_num  # 请求的page
        shanum, yunum = divmod(self.total_count, self.per_page_num)  # 计算商数和余数

        # 生成要展示的页码数
        if yunum:
            self.page_num_count = shanum + 1
        else:
            self.page_num_count = shanum

        # 如果页码数小于等于零 或者大于总页码数 让他不出问题
        if self.page_num <= 0:
            self.page_num = 1
        elif page_num > self.page_num_count:
            self.page_num = self.page_num_count

        half_show = self.page_num_show//2  # 分页按钮中心两端的数量

        if page_num - half_show <= 0:
            start_page_num = 1
            end_page_num = self.page_num_show + 1
        elif page_num + half_show > self.page_num_count:
            start_page_num = self.page_num_count - self.page_num_show + 1
            end_page_num = self.page_num_count + 1
        else:
            start_page_num = page_num - half_show
            end_page_num = page_num + half_show + 1
        self.start_page_num = start_page_num  # 开始位置
        self.end_page_num = end_page_num  # 结束位置

    @property
    def start_data_num(self):
        return (self.page_num-1)*self.per_page_num

    @property
    def end_data_num(self):
        return self.page_num*self.per_page_num

    def page_html(self):
        page_num_range = range(self.start_page_num, self.end_page_num)
        page_html = ''
        # 开头标签样式之类
        page_per_html = '''
            <nav aria-label="Page navigation">
            <ul class="pagination">'''
        page_html += page_per_html
        # 上一页
        if self.page_num > 1:
            per_page = f'''
                <li><a href="{self.base_url}?page={self.page_num-1}" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span></a></li>'''
            page_html += per_page
        # 循环添加按钮
        for page in page_num_range:
            if self.page_num == page:
                page_num_html = f'''
                    <li class="active"><a href="{self.base_url}?page={page}">{page}</a></li>
                '''
            else:
                page_num_html = f'''
                    <li><a href="{self.base_url}?page={page}">{page}</a></li>
                '''
            page_html += page_num_html
        # 下一页
        if self.page_num < self.page_num_count:
            next_page = f'''
            <li><a href="{self.base_url}?page={self.page_num+1}" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
            </a></li>
            '''
            page_html += next_page
        # 标签样式收尾
        page_next_html = '''</ul></nav>'''
        page_html += page_next_html
        
        return mark_safe(page_html) # 将最后生成的html标签返回给前端

 

posted @ 2020-07-16 20:50  CatdeXin  阅读(182)  评论(0)    收藏  举报