Django -分页功能的两种实现

文章目录

  • 1. Django文档中分页Paginator模块的一些方法
  • 2. 分页
    • 2.1 前后端分离写法
      • (1) 每页显示数据和页码关联实现
      • (2) 页码显示功能实现
      • (3) 分页功能汇总
    • 2.2 前后端合在一起写法
      • (1) 自定义分页功能
      • (2) views视图部分
      • (3) 需要引入分页功能的模板部分

1. Django文档中分页Paginator模块的一些方法

from django.core.paginator import Paginator    # 导入模块
objects = ['john', 'paul', 'george', 'ringo']
p = Paginator(objects, 2)   #  实例化对象 Paginator(对象, 每页放多少数据) 

>>> p.count   # 获取总的数据有多少条
4
>>> p.num_pages  # 总的有多少页
>>> p .range()  # 页面范围

>>> type(p.page_range)   #  获取总的页码范围

>>> p.page_range
range(1, 3)

>>> page1 = p.page(1)  #  获取第1页 对象
>>> page1

>>> page1.object_list   # 获取第1页的所有数据
['john', 'paul']

>>> page2 = p.page(2)  #  获取第2页 对象
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()  # 查看当前页是否还有下一页
False
>>> page2.has_previous()  # 查看当前页是否有上一页
True
>>> page2.has_other_pages()  # 查看是否还有其他页码
True
>>> page2.next_page_number()  # 获取该页下一页的页码数
Traceback (most recent call last):
...


EmptyPage: That page contains no results
>>> page2.previous_page_number()  # 获取该页上一页的页码数
1
>>> page2.start_index() # The 1-based index of the first item on this page 
3
>>> page2.end_index() # The 1-based index of the last item on this page
4

2. 分页

2.1 前后端分离写法

(1) 每页显示数据和页码关联实现


from django.shortcuts import render
from django.core.paginator import Paginator

from mydatabase.models import Student


def paginator(request):

	"""
	要实现分页功能在views视图函数中只需要获取到:
		1. 前端传来的每页显示多少条数据per_page
		2. 前端传来的当前页page
		3. Paginator的数据实例对象paginator
		4. 数据的总页数total_page
		5. 当前页的数据obj_data
	当获取到这几个数据后就可以实现页面显示每页数据条数和页码关联的功能了
		
	"""
	-- 获取到分页paginator 对象
	 	1. 从数据库中拿取数据 
	 	 	data_obj = Student.objects.all()/filter(条件).order_by("-create_time") #按照添加时间反向排序
		2. 获取前端传来的每页放多少条数据per_page,同时设置一个默认值防止报错
	 		per_page = request.GET.get('per_page',10)
		3. 实例化paginator对象
	 		paginator = Paginator(data_obj , per_page)
	 		
	-- 获取到总的页数
			total_page = paginator.num_pages
			
	-- 获取到当前页的数据
		1. 获取前端传来的当前页page,同时设置一个默认值防止报错
			page = request.GET.get("page", 1) 
		2. 获取到当前页的数据
			obj_data = paginator.paginator.get_page(page)  
	return render(request,'pagintor.html',
				context={
						"obj_data ": obj_data,
						"per_page": per_page,
                        "page": page,
                        "total_page": total_page, 
				})

(2) 页码显示功能实现

这里采用页码当前页+前面页码和后面页码两部分来分析页码显示情况:
Django -分页功能的两种实现_第1张图片
同时采用自定义pagination标签:

from django import template

@register.inclusion_tag("self_pagination.html", takes_context=True)
def pagination(context):
	"""
	根据上面的分析代码情况如下
	"""
    total_page = context["total_page"] 	# 获取views传来的总数据
 	page = int(context["page"]) 		# 当前页面
    num = 3                				# 当前页两边各显示多少页码
    page_list = []  					# 页码显示数列表

    # 1 判断当前页+左边部分
    # 1.1 当前页小于num时,只有左边
    if page-num <= 0:
        for i in range(1, page+1):
            page_list.append(i)
    # 1.2  当前页大于num时,
    else:
        for i in range(page-num, page+1):
            page_list.append(i)
            
    # 2 判断右边部分
    # 2.1 当当前页+num大于等于总页数时,只有右边
    if page+num >= total_page:
        for i in range(page+1, total_page+1):
            page_list.append(i)
    # 2.2  当前页大于num时,
    else:
        for i in range(page+1, page+num+1):
            page_list.append(i)

    return {
            "page_list": page_list,
            "page": page,
            "per_page": context["per_page"],
            "total_page": total_page,
    }

自定义模板部分:

<div class="btn-group">
    <nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
             <a href="{% if page > 1 %}{{ request.path }}?per_page={{ per_page }}&page={{ page|add:"-1" }}{% endif %}" aria-label="Previous">
                <span aria-hidden="true">上一页</span>
            </a>
        </li>
        {% for page_num in page_list %}
            <li {% if page_num == page %}class="active"{% endif %}><a href="{{ request.path }}?per_page={{ per_page }}&page={{ page_num }}">{{ page_num }}</a></li>
        {% endfor %}
        <li>
          <a href="{% if page < total_page %}{{ request.path }}?per_page={{ per_page }}&page={{ page|add:"1" }}{% endif %}" aria-label="Next">
                <span aria-hidden="true">下一页</span>
          </a>
        </li>
    </ul>
</nav>
</div>
<div class="btn-group" style="margin-top: -5px;">
    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    {{ per_page }}/<span class="caret"></span>
   </button>
   <ul class="dropdown-menu">
	   """
	   	这里设置每页显示数据条数选择可以自己根据需要设置数据
	   """
        <li><a href="{{ request.path }}?per_page=3">3/</a></li>
        <li><a href="{{ request.path }}?per_page=5">5/</a></li>
        <li><a href="{{ request.path }}?per_page=10">10/</a></li>
   </ul>
</div>

在需要放置分页功能的模板中只需要 {% pagination %}引入我们自定义的包含标签就完成了。
代码汇总:

(3) 分页功能汇总

views视图部分

from django.shortcuts import render
from django.core.paginator import Paginator

from mydatabase.models import Student

def paginator(request):
	data_obj = Student.objects.all().order_by('-create_time')   # 数据源
	per_page = request.GET.get("per_page", 10)  				# 获取每页数据放几条
    paginator = Paginator(data_obj , per_page)  		# 获取paginator对象
    total_page = paginator.num_pages                  		# 获取总的页数
    page = request.GET.get("page", 1)                  		# 获取当前页
    obj_data = paginator.get_page(page)             	# 获取当前页数据

    return render(request, "pagintor.html",
                  context={"obj_data ": obj_data ,
                           "per_page": per_page,
                           "page": page,
                           "total_page": total_page,
                           }
                  )

自定义pagination标签部分

from django import template

@register.inclusion_tag("self_pagination.html", takes_context=True)
def pagination(context):
	"""
	根据上面的分析代码情况如下
	"""
    total_page = context["total_page"] 	# 获取views传来的总数据
 	page = int(context["page"]) 		# 当前页面
    num = 3                				# 当前页两边各显示多少页码
    page_list = []  					# 页码显示数列表

    # 1 判断当前页+左边部分
    # 1.1 当前页小于num时,只有左边
    if page-num <= 0:
        for i in range(1, page+1):
            page_list.append(i)
    # 1.2  当前页大于num时,
    else:
        for i in range(page-num, page+1):
            page_list.append(i)
            
    # 2 判断右边部分
    # 2.1 当当前页+num大于等于总页数时,只有右边
    if page+num >= total_page:
        for i in range(page+1, total_page+1):
            page_list.append(i)
    # 2.2  当前页大于num时,
    else:
        for i in range(page+1, page+num+1):
            page_list.append(i)

    return {
            "page_list": page_list,
            "page": page,
            "per_page": context["per_page"],
            "total_page": total_page,
    }

自定义self_pagination.html模板部分

<div class="btn-group">
    <nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
             <a href="{% if page > 1 %}{{ request.path }}?per_page={{ per_page }}&page={{ page|add:"-1" }}{% endif %}" aria-label="Previous">
                <span aria-hidden="true">上一页</span>
            </a>
        </li>
        {% for page_num in page_list %}
            <li {% if page_num == page %}class="active"{% endif %}><a href="{{ request.path }}?per_page={{ per_page }}&page={{ page_num }}">{{ page_num }}</a></li>
        {% endfor %}
        <li>
          <a href="{% if page < total_page %}{{ request.path }}?per_page={{ per_page }}&page={{ page|add:"1" }}{% endif %}" aria-label="Next">
                <span aria-hidden="true">下一页</span>
          </a>
        </li>
    </ul>
</nav>
</div>
<div class="btn-group" style="margin-top: -5px;">
    <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    {{ per_page }}/<span class="caret"></span>
   </button>
   <ul class="dropdown-menu">
	   """
	   	这里设置每页显示数据条数选择可以自己根据需要设置数据
	   """
        <li><a href="{{ request.path }}?per_page=3">3/</a></li>
        <li><a href="{{ request.path }}?per_page=5">5/</a></li>
        <li><a href="{{ request.path }}?per_page=10">10/</a></li>
   </ul>
</div>

需要使用分页功能的模板部分

# 循环拿到的数据
<table>
	<thead>
		<tr>
		<th>序号</th>
		<th>名字</th>
		</tr>
	</thead>
	<tbody>
		<tr>
		<td>{{ forloop.counter }}</td>
		<td>{{ obj_data.name}}</td>
		</tr>
	</tbody>
</table>
{% pagination %}   # 引入分页功能

方式1的分页功能就算实现了

2.2 前后端合在一起写法

这里将分页功能和每页显示多少条数据显示都封装在一起。

(1) 自定义分页功能

class CustomPagination(object):
    """
    自定义分页将分页的页码数和每页存放多少数据封装进类中
    """
    def __init__(self, current_page, total_page, path, item_page, max_page_num=7, per_page=10):
        self.page = int(current_page)  # 当前页
        self.path = path             # 数据访问路径
        self.page_number = max_page_num  # 页码显示数量
        self.per_page = int(per_page)        # 每页数据显示多少个
        self.total_page = total_page  # 总的有多少页
        self.item_page = item_page      # 每页显示多少选项


    @property
    def pager_num_range(self):
        """
        显示页面个数这里时按照总的需要显示的页码个数情况来分析写的
        :return:
        """
        page_list = []
        # 1. 当总页数小于显示最多的页面page_number时
        if self.total_page < self.page_number:
            for i in range(1, self.total_page+1):
                page_list.append(i)

        # 2. 当总页数大于显示最多的页面page_number时
        else:
            # 2.0 判断一半的最多显示页面为多少
            half_page_number = int(self.page_number) // 2

            # 2.1 当当前页数<=一半显示页面时,数字显示页面不变
            if self.page <= half_page_number:
                for i in range(1, self.page_number + 1):
                    page_list.append(i)

            # 2.2 当当前页数大于一半显示页面,并且当前页数+半值<总页面数时,当前页面就一直在中间保持
            elif self.page > half_page_number and self.page + half_page_number <= self.total_page:
                for i in range(self.page - half_page_number,self.page+half_page_number+1):
                    page_list.append(i)

            # 2.3 当当前页数+半值>页面总数时,数字显示为总页面数减去page_number到总页数
            elif (self.page + half_page_number) > self.total_page:
                for i in range(self.total_page - self.page_number, self.total_page+ 1):
                    page_list.append(i)

        return page_list

    def page_str(self):
        """
        生成html字符串
        :return:
        """
        page_html_list = []
        # 前面的包裹div起始
        html_div_start = '
'
page_html_list.append(html_div_end) # 下拉框div起始 select_div_start = '
'
page_html_list.append(select_div_end) return ''.join(page_html_list)

(2) views视图部分

from django.shortcuts import render

from plugs.custom_paginal import CustomPagination  # 导入自定义的分页类
from mydatabase.models import Student

def paginator(request):
	data_obj = Student.objects.all().order_by('-create_time')   # 数据源
	per_page = request.GET.get("per_page", 10)  				# 获取每页数据放几条
    paginator = Paginator(data_obj , per_page)  		# 获取paginator对象
    total_page = paginator.num_pages                  		# 获取总的页数
    page = request.GET.get("page", 1)                  		# 获取当前页
    obj_data = paginator.get_page(page)             	# 获取当前页数据
    
	item_page = [1, 2, 5]    # 每页显示数据条数列表
    path = request.path     # 数据跳转地址
    custom_pagination = CustomPagination(page, total_page, path, item_page, per_page=per_page)  # 实例化自定义分页对象

    return render(request, "pagintor.html",
                  context={"obj_data ": obj_data,
                           "custom_pagination": custom_pagination,
                           }
                  )

(3) 需要引入分页功能的模板部分

# 循环拿到的数据
<table>
	<thead>
		<tr>
		<th>序号</th>
		<th>名字</th>
		</tr>
	</thead>
	<tbody>
		<tr>
		<td>{{ forloop.counter }}</td>
		<td>{{ obj_data.name}}</td>
		</tr>
	</tbody>
</table>
{{ custom_pagination.page_str|safe }}  # 引入分页功能

你可能感兴趣的:(Django -分页功能的两种实现)