Django 分页加载数据

分页加载

Django 分页加载数据

普通实现

向book表添加大量数据

class Book(models.Model):
    title = models.CharField(max_length=32)

    def __str__(self):
        return self.title

    class Meta:
        db_table = 'book'

        
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TestProject.settings")

    import django
    django.setup()

    books = (models.Book(title='图书{}'.format(i)) for i in range(300))
    models.Book.objects.bulk_create(books)

template

<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>序号</th>
            <th>id</th>
            <th>书名</th>
        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.id }}</td>
                <td>{{ book.title }}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <nav aria-label="Page navigation">
        <ul class="pagination">
            {{ html_page|safe }}
        </ul>
    </nav>
</div>

分页加载具体代码

from app02 import models
from django.shortcuts import render


def books(request):
    # 从url中获取当前页码数
    current_page = 1
    try:
        current_page = int(request.GET.get('page'))
    except Exception as e:
        current_page = 1

    # 总数量
    total_count = models.Book.objects.count()

    # 每页数量
    per_count = 10

    # 总页数
    total_page, more = divmod(total_count, per_count)
    if more:
        total_page += 1

    # 每页显示最大页码数,(左右对称定义奇数)
    max_page_num = 11
    half_page_num = max_page_num // 2

    # 计算当前页面的页码范围
    if max_page_num >= total_page:
        # 总页码书小于最大显示页码数
        start_page = 1
        end_page = total_page
    elif current_page + half_page_num >= total_page:
        # 右边越界
        end_page = total_page
        start_page = total_page - max_page_num
    elif current_page - half_page_num <= 1:
        # 左边越界
        start_page = 1
        end_page = max_page_num
    else:
        # 正常状态
        start_page = current_page - half_page_num
        end_page = current_page + half_page_num

    start_index = (current_page - 1) * per_count
    end_index = current_page * per_count

    book_list = models.Book.objects.all()[start_index:end_index]

    page_html_list = []

    # 加首页页码
    first_li = '<li><a href="/books/?page=1">首页</a></li>'
    page_html_list.append(first_li)

    # 加上一页页码
    if current_page == 1:
        prev_li = '<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>'
    else:
        prev_li = '<li><a href="/books/?page={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
            current_page - 1)
    page_html_list.append(prev_li)

    # 加中间页码
    for i in range(start_page, end_page + 1):
        if i == current_page:
            li = '<li class="active"><a href="/books/?page={0}">{0}</a></li>'.format(i)
        else:
            li = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i)
        page_html_list.append(li)

    # 加下一页页码
    if current_page == total_page:
        next_li = '<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>'
    else:
        next_li = '<li><a href="/books/?page={}"><span aria-hidden="true">&raquo;</span></a></li>'.format(
            current_page + 1)
    page_html_list.append(next_li)

    # 加尾页页码
    end_li = '<li><a href="/books/?page={}">尾页</a></li>'.format(total_page)
    page_html_list.append(end_li)
    html_page = ''.join(page_html_list)

    return render(request, 'books.html', {'book_list': book_list, 'html_page': html_page})

封装实现

class Page:
    def __init__(self, current_page, total_count, base_url, per_page=10, max_page_num=11):
        """
        :param current_page:当前页
        :param total_count: 总数量
        :param base_url: 请求url
        :param per_page: 每页数量
        :param max_page_num:每页最大页码数
        """

        # 当前页
        try:
            self.current_page = int(current_page)
        except Exception as e:
            self.current_page = 1
        # 每页数量
        self.per_page = per_page
        # 总页数
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        self.total_page = total_page
        # 最大页码数
        self.max_page_num = max_page_num
        self.half_page_num = max_page_num // 2
        self.base_url = base_url

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page

    @property
    def end(self):
        return self.current_page * self.per_page

    def page_html(self):
        if self.total_page <= self.max_page_num:
            # 总页码数小于最大页码数
            start_page = 1
            end_page = self.total_page
        elif self.current_page + self.half_page_num >= self.total_page:
            # 右边越界
            end_page = self.total_page
            start_page = self.total_page - self.max_page_num
        elif self.current_page - self.half_page_num <= 1:
            # 左边越界
            start_page = 1
            end_page = self.max_page_num
        else:
            # 正常
            start_page = self.current_page - self.half_page_num
            end_page = self.current_page + self.half_page_num

        # 生成页码html
        page_html_list = []

        # 添加首页页码
        first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url)
        page_html_list.append(first_li)

        # 添加上一页
        if self.current_page == 1:
            prev_li = '<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>'
        else:
            prev_li = '<li><a href="{}?page={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(
                self.base_url, self.current_page - 1)
        page_html_list.append(prev_li)

        # 添加中间页码
        for i in range(start_page, end_page + 1):
            if i == self.current_page:
                li = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            else:
                li = '<li ><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
            page_html_list.append(li)

        # 添加下一页
        if self.current_page == self.total_page:
            next_li = '<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>'
        else:
            next_li = '<li><a href="{}?page={}"><span aria-hidden="true">&raquo;</span></a></li>'.format(
                self.base_url, self.current_page + 1)
        page_html_list.append(next_li)

        # 添加尾页
        end_li = '<li><a href="{}?page={}">尾页</a></li>'.format(self.base_url, self.total_page)
        page_html_list.append(end_li)

        return ''.join(page_html_list)

使用示例:

from utils.Pagination import Page


def books(request):
    current_page = int(request.GET.get('page'))
    total_count = models.Book.objects.count()
    page_obj = Page(current_page, total_count, request.path_info)
    book_list = models.Book.objects.all()[page_obj.start:page_obj.end]
    page_html = page_obj.page_html()
    return render(request, 'books.html', {'book_list': book_list, 'html_page': page_html})

Django 内置分页

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger


def books(request):
    current_page = request.GET.get('page')
    paginator = Paginator(models.Book.objects.all(), 10)
    """
    paginator.per_page  # 每页显示数量
    paginator.count  # 数据总数
    paginator.num_pages  # 总页数
    paginator.page_range  # 页码范围
    paginator.page  # 页码范围
    """
    try:
        book_list = paginator.page(current_page)
        """
        book_list.has_previous()  # 是否有上一页
        book_list.has_next()  # 是否有下一页
        """
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)
    return render(request, 'books.html', {'book_list': book_list})