1. 概述

分页,就是当我们在页面中显示一些信息列表,内容过多,一个页面显示不完,需要分成多个页面进行显示时,使用的技术就是分页技术。

在django项目中,一般是使用3种分页的技术:

  1. 自定义分页功能,所有的分页功能都是自己实现
  2. django的插件 django-pagination 实现
  3. django自带的分页器 paginator
    这里将会讲解第三种

2. 分页器相关对象

分页器的对象在 django/core/paginator.py 模块中,主要包括Paginator类和Page类:

2.1 Paginator类

  1. 初始化方法_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错误
  1. 方法
  1. get_page(self, number)
  • numer:指定页码数,正确值应该是大于等于1的整数

返回指定number的Page对象,同时还处理超出范围和无效页码,如果number不是数字,则返回第一页,如果number为负数或大于最大页数,则返回最后一页。

  1. page(self, number)
  • numer:指定页码数,正确值应该是大于等于1的整数

返回指定number的Page对象,不处理异常,如果number无效,则抛出 InvalidPage 错误

  1. 属性
  1. count:项目总条数,调用该属性时,优先调用object_list的count()方法,没有count()方法才尝试len(object_list)方法
  2. num_pages:总页码数
  3. page_range:从1开始的页码迭代器,代码:range(1, self.num_pages + 1)

2.2 Page类

一般情况下,不会手动实例化该类,而是通过Paginator的page或者get_page方法获取

  1. 初始化方法_init_(self, object_list, number, paginator):
  • object_list:当页显示的object_list对象,object_list可以是QuerySet、带有count()或_len_()方法的列表、元组或其它可切片的对象
  • number:页码数
  • paginator:Paginator类的实例
  1. 方法
    主要的方法都是用来做逻辑判断的,以此来决定页面中显示的诸如:上一页、下一页,首页,末页等
  1. has_next():如果有下一页则返回True
  2. has_previous():如果有上一页,则返回True
  3. has_other_pages():如果有上一页或者下一页,则返回True
  4. next_page_number():返回下一页编号,如果下一页不存在则引发 InvalidPage 错误
  5. previous_page_number():返回上一页编号,如果上一页不存在则引发 InvalidPage 错误
  6. start_index() :返回页面上第一个对象的从1开始的索引,相对于分页器列表中的所有对象。例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的start_index返回3
  7. end_index() :返回页面上最后一个对象的从1开始的索引,相对于分页器列表中的所有对象。例如,当为每页包含2个对象的5个对象的列表进行分页时,第二个页面Page对象的end_index返回4
  1. 属性
    其实就是初始化方法中的3个参数
  1. object_list:对应的object_list
  2. number:该对象的所处的页码数,从1开始
  3. paginator:关联的Paginator实例

3. 项目中应用

翻页显示数据实现
orphans参数的使用——让最后一页的少数据去到前一面

  1. 新建django项目:paginator_study,子应用:paginator_app
  2. 在mysql数据库新建 paginator_study 库
  3. settings中配置数据库:
DATABASES = {
       'default': {
           'ENGINE': 'django.db.backends.mysql',
           'NAME': 'paginator_study',
           'USER': 'root',
           'PASSWORD': '123456',
           'HOST': '127.0.0.1',
           'PORT': '3306',
       }
   }
  1. 建立模型并随机生成数据方法:
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 django写分页 django分页功能_数据库

  1. 迁移数据库
python manage.py makemigrations
   
   python manage.py migrate paginator_app
  1. 配置templates在settings
import os
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR,'templates')],
  1. 配置分页在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})