1. 概述
分页,就是当我们在页面中显示一些信息列表,内容过多,一个页面显示不完,需要分成多个页面进行显示时,使用的技术就是分页技术。
在django项目中,一般是使用3种分页的技术:
- 自定义分页功能,所有的分页功能都是自己实现
- django的插件 django-pagination 实现
- django自带的分页器 paginator
这里将会讲解第三种
2. 分页器相关对象
分页器的对象在 django/core/paginator.py 模块中,主要包括Paginator类和Page类:
2.1 Paginator类
- 初始化方法_init_(self, object_list, per_page, orphans=0,allow_empty_first_page=True):
- object_list:可以是QuerySet、带有count()或_len_()方法的列表、元组或其它可切片的对象,如果是QuerySet,应该进行排序,使用order_by()子句或者有默认的ordering
- per_page:每个页面上显示的项目数目,不包括orphans部分
- orphans:默认为0,如果最后一页显示的数目小于等于该数值,那么则将最后一页的内容(假设数为N)添加到倒数第二页中去,这样的话倒数第二页就成了最后一页,显示的数目为:per_page+N
- allow_empty_first_page:默认为True,允许第一页显示空白内容,如果设置为False,那么当object_list为空时,抛出EmptyPage错误
- 方法
- get_page(self, number)
- numer:指定页码数,正确值应该是大于等于1的整数
返回指定number的Page对象,同时还处理超出范围和无效页码,如果number不是数字,则返回第一页,如果number为负数或大于最大页数,则返回最后一页。
- page(self, number)
- numer:指定页码数,正确值应该是大于等于1的整数
返回指定number的Page对象,不处理异常,如果number无效,则抛出 InvalidPage 错误
- 属性
- count:项目总条数,调用该属性时,优先调用object_list的count()方法,没有count()方法才尝试len(object_list)方法
- num_pages:总页码数
- page_range:从1开始的页码迭代器,代码:range(1, self.num_pages + 1)
2.2 Page类
一般情况下,不会手动实例化该类,而是通过Paginator的page或者get_page方法获取
- 初始化方法_init_(self, object_list, number, paginator):
- object_list:当页显示的object_list对象,object_list可以是QuerySet、带有count()或_len_()方法的列表、元组或其它可切片的对象
- number:页码数
- paginator:Paginator类的实例
- 方法
主要的方法都是用来做逻辑判断的,以此来决定页面中显示的诸如:上一页、下一页,首页,末页等
- has_next():如果有下一页则返回True
- has_previous():如果有上一页,则返回True
- has_other_pages():如果有上一页或者下一页,则返回True
- next_page_number():返回下一页编号,如果下一页不存在则引发 InvalidPage 错误
- previous_page_number():返回上一页编号,如果上一页不存在则引发 InvalidPage 错误
- start_index() :返回页面上第一个对象的从1开始的索引,相对于分页器列表中的所有对象。例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的start_index返回3
- end_index() :返回页面上最后一个对象的从1开始的索引,相对于分页器列表中的所有对象。例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的end_index返回4
- 属性
其实就是初始化方法中的3个参数
- object_list:对应的object_list
- number:该对象的所处的页码数,从1开始
- paginator:关联的Paginator实例
3. 项目中应用
翻页显示数据实现
orphans参数的使用——让最后一页的少数据去到前一面
- 新建django项目:paginator_study,子应用:paginator_app
- 在mysql数据库新建 paginator_study 库
- settings中配置数据库:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'paginator_study',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
- 建立模型并随机生成数据方法:
from django.db import models
import random
import string
# Create your models here.
class Student(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
sex = models.IntegerField(choices=((1,'男'),(2,'女')),default=1)
card_no = models.CharField(max_length=18)
@classmethod
def insert_student_data(cls,num):
# 随机生成字符串
def random_str(str,length):
return ''.join(random.choices(str,k=length)) # 按照str内容,随机插入length个数据
student_list = []
for i in range(num):
student_list.append(Student(
name = random_str(string.ascii_lowercase, 10),# 从小写字母中,随机插入10位
age = random.randint(18,30),
sex = random.choice([1,2]),
card_no = random_str(string.digits,18)
))
Student.objects.bulk_create(student_list)
Django调用函数单独执行的方法
- 迁移数据库
python manage.py makemigrations
python manage.py migrate paginator_app
- 配置templates在settings
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
- 配置分页在settings
# 配置分页页数
PAGE_SIZE = 10
# 配置最后一页最小数
ORPHANS = 5
url
from django.contrib import admin
from django.urls import path,include
from . import views
urlpatterns = [
path('student_list/',views.student_list),
path('student_page_list/',views.student_page_list)
]
templates
<!DOCTYPE html>
<html lang="en">
{% load static %}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="{% static 'paginator_app/css/page_style.css' %}">
</head>
<body>
<div>
<table>
<tr>
<th>序号</th>
<th>学生姓名</th>
<th>年龄</th>
<th>性别</th>
<th>身份证号</th>
</tr>
{% for student in student_page.object_list %}
<tr>
<!-- <td>{{forloop.counter}}</td> -->
<td>{{student_page.start_index|add:forloop.counter0}}</td>
<td>{{student.name}}</td>
<td>{{student.age}}</td>
<td>{{student.sex}}</td>
<td>{{student.card_no}}</td>
</tr>
{% endfor %}
</table>
<nav>
<ul>
<li><a href="?num=1"><span>首页</span></a></li>
<li>
{%if student_page.has_previous %}
<a href="?num={{student_page.previous_page_number}}"><span>上一页</span></a>
{% else %}
<span>上一页</span>
{%endif%}
</li>
{% for i in page_range_list%}
{% if student_page.number == i%}
<li><a href="?num={{i}}"><span><strong>{{i}}</strong></span></a></li>
{%else%}
<li><a href="?num={{i}}"><span>{{i}}</span></a></li>
{%endif%}
{%endfor%}
<li>
{% if student_page.has_next %}
<a href="?num={{student_page.next_page_number}}"><span>下一页</span></a>
{% else %}
<span>下一页</span>
{% endif %}
</li>
<li><a href="?num={{student_page.paginator.num_pages}}"><span>末页</span></a></li>
总共是{{student_page.paginator.num_pages}}页
当前是第{{student_page.number}}页
</ul>
</nav>
</div>
</body>
</html>
views
from django.shortcuts import render
from .models import Student
from django.core.paginator import Paginator, Page
from django.conf import settings
# Create your views here.
def student_list(request):
# 查询学生列表
student_list = Student.objects.all()
return render(request, 'paginator_app/student_list.html',{'student_list':student_list})
def get_range_list(num, total_page, size = 9):
min = num-int(size/2)
min = min if min>=1 else 1
max = min + size -1
max = max if max <= total_page else total_page
return range(min,max+1)
def student_page_list(request):
# 获取当前查询的是第几页
num = request.GET.get('num')
student_list = Student.objects.all()
# 创建Paginator实例对象
paginator = Paginator(student_list, settings.PAGE_SIZE, settings.ORPHANS)
# paginator = Paginator(student_list,10)
# 获取Page对象
student_page = paginator.get_page(num)
page_range_list = get_range_list(student_page.number,paginator.num_pages,settings.RANGE_LIST_SIZE)
return render(request, 'paginator_app/student_page.html',{'student_page':student_page,'page_range_list':page_range_list})