分頁器組件

準備

models.pycss

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=32)
    books = models.ManyToManyField(to="Book")

    def __str__(self):
        return self.name

    class Meta:
        db_table = "author"

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

    def __str__(self):
        return self.title

    class Meta:
        db_table = "book"

urls.pyhtml

from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^books/$', views.books),
]

books.htmlpython

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>書籍列表</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>序號</th>
                    <th>id</th>
                    <th>書名</th>
                </tr>
            </thead>
            <tbody>
            {% for book in books %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ book.id }}</td>
                    <td>{{ book.title }}</td>
                </tr>
            {% endfor %}

            </tbody>
        </table>
    </div>
</body>
</html>

批量插入數據

import os
import sys

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

    import django
    django.setup()

    from app01 import models
    # 批量建立
    # 有100個書籍對象
    objs = [models.Book(title="書本{}".format(i)) for i in range(100)]

    # 在數據庫中批量建立, 10次一提交
    models.Book.objects.bulk_create(objs, 10)

展現全部的數據

from django.shortcuts import render
from app01 import models

def books(request):
    all_book = models.Book.objects.all()
    return render(request, "books.html", {"books": all_book})

需求

如今需求是作一個相似博客園的分頁git

當點擊第一頁的時候,URL 顯示爲 /books/?page=1/ ,並顯示第一頁的數據,一頁展現 10 條數據github

展現

規律

能夠在視圖函數裏使用切片操做,當要展現第一頁的數據,即 1-10 條數據,它的索引是 [0:10]數據庫

from django.shortcuts import render
from app01 import models

def books(request):
    all_book = models.Book.objects.all()[:10]
    return render(request, "books.html", {"books": all_book})

展現第一頁的數據,即 11-20 條數據,它的索引是 [10:20]django

from django.shortcuts import render
from app01 import models

def books(request):
    all_book = models.Book.objects.all()[10:20]
    return render(request, "books.html", {"books": all_book})

因此,它的規律是:bootstrap

from django.shortcuts import render
from app01 import models

def books(request):
    # 從URL取參數
    page_num = request.GET.get("page")
    page_num = int(page_num)

    # 定義兩個變量保存數據從哪取到哪
    data_start = (page_num-1) * 10
    data_end = page_num * 10

    all_book = models.Book.objects.all()[data_start: data_end]
    return render(request, "books.html", {"books": all_book})

增長樣式

增長 bootstrap 樣式,顯示可點擊跳轉的頁碼。首先要算出總頁碼數app

能夠根據 divmod() 計算,當有 20 條數據,每頁展現 10 條,計算出 (2, 0) ,當有 21 條數據,計算出 (2, 1) ,計算出的值裏右邊的爲 0,左邊的就是頁碼數,不然左邊的頁碼數就加一。函數

而後本身拼接一個 a 標籤,將拼接好的傳入模板

from django.shortcuts import render
from app01 import models

def books(request):
    # 從URL取參數
    page_num = request.GET.get("page")
    page_num = int(page_num)

    # 定義兩個變量保存數據從哪取到哪
    data_start = (page_num - 1) * 10
    data_end = page_num * 10

    # 每一頁顯示多少條數據
    per_page = 10

    # 總數據是多少
    total_count = models.Book.objects.all().count()
    # 總共須要多少頁碼來展現
    total_page, m = divmod(total_count, per_page)
    if m:
        total_page += 1

    all_book = models.Book.objects.all()[data_start: data_end]

    # 拼接分頁的html代碼
    html_str_list = []
    for i in range(1, total_page + 1):
        tmp = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i)
        html_str_list.append(tmp)

    page_html = "".join(html_str_list)

    return render(request, "books.html", {"books": all_book, "page_html": page_html})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>書籍列表</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>序號</th>
            <th>id</th>
            <th>書名</th>
        </tr>
        </thead>
        <tbody>
        {% for book in books %}
            <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">
            <li>
                <a href="#" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                </a>
            </li>
            {{ page_html | safe }}
            <li>
                <a href="#" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                </a>
            </li>
        </ul>
    </nav>
</div>
</body>
</html>

添加多條數據

以上即是一個簡單分頁的實現,這是數據比較少的狀況,如今向數據庫添加至 1000 條數據,再進行頁面展現

這顯然是不合理的,博客園中頁碼中間是用省略號,省略號前面的頁碼通常都爲奇數,且始終只有 200 頁

因此這裏的需求是,展現的頁碼數固定爲 11 頁,當前所在頁碼的先後頁碼數對稱。假如當前在第六頁,前面展現五個,後面也展現五個,也就是 1-11 頁

有了展現的開始頁碼和結束頁碼,拼接 html 代碼時也要有所改動

多條數據的首尾頁碼

而後考慮首尾的問題,若是當前頁減一半比 1 小,仍是須要固定 1-11 頁

若是當前頁比 100 大,後面再也不顯示頁碼

加上首頁、尾頁、上一頁、下一頁

這時,當處於第一頁時,上一頁不可點擊,一樣,處於最後一頁時,下一頁也不可點擊。看起來實現了分頁的操做,但此時刪除至只有一條數據,又出現了頁碼爲負數的狀況。

因此要有一個判斷

# 頁面上總共展現多少頁碼
max_page = 11
# 當總頁碼數小於展現的頁碼數
if total_page < max_page:
    max_page = total_page

這樣,便可以訪問了,再作一些完善,好比用戶輸入頁碼數不是數字,或者大於最大的頁碼數,讓當前頁碼加一個 active 類等。

最終代碼

from django.shortcuts import render
from app01 import models


# Create your views here.

def books(request):
    # 從URL取參數
    page_num = request.GET.get("page")

    # 每一頁顯示多少條數據
    per_page = 10

    # 總數據是多少
    total_count = models.Book.objects.all().count()
    # 總共須要多少頁碼來展現
    total_page, m = divmod(total_count, per_page)
    if m:
        total_page += 1

    try:
        page_num = int(page_num)
        # 若是輸入的頁碼超過了最大的頁碼數,默認返回最後一頁
        if page_num > total_page:
            page_num = total_page
    except Exception as e:
        # 當輸入的頁碼不是數字的時候,默認返回第一頁的數據
        page_num = 1

    # 定義兩個變量保存數據從哪取到哪
    data_start = (page_num - 1) * 10
    data_end = page_num * 10

    # 頁面上總共展現多少頁碼
    max_page = 11
    if total_page < max_page:
        max_page = total_page

    half_max_page = max_page // 2
    # 頁面上展現的頁碼從哪開始
    page_start = page_num - half_max_page
    # 頁面上展現的頁碼到哪結束
    page_end = page_num + half_max_page

    # 若是當前頁減一半 比1小
    if page_start <= 1:
        page_start = 1
        page_end = max_page

    # 若是當前頁加一半 比總頁碼數還大
    if page_end >= total_page:
        page_end = total_page
        page_start = total_page - max_page + 1

    all_book = models.Book.objects.all()[data_start: data_end]

    # 拼接分頁的html代碼
    html_str_list = []
    # 加上第一頁
    html_str_list.append('<li><a href="/books/?page=1">首頁</a></li>')

    # 加上一頁,上一頁就是當前頁減一
    # 判斷,若是第一頁,就沒有上一頁
    if page_num <= 1:
        html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
    else:
        html_str_list.append(
            '<li><a href="/books/?page={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num - 1))

    for i in range(page_start, page_end + 1):
        # 若是是當前頁,加一個active樣式類
        if i == page_num:
            tmp = '<li class="active"><a href="/books/?page={0}">{0}</a></li>'.format(i)
        else:
            tmp = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i)
        html_str_list.append(tmp)

    # 加下一頁,下一頁就是當前頁加一
    # 判斷,若是是最後一頁,就沒有下一頁
    if page_num >= total_page:
        html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>')
    else:
        html_str_list.append(
            '<li><a href="/books/?page={}"><span aria-hidden="true">&raquo;</span></a></li>'.format(page_num + 1))

    # 加最後一頁
    html_str_list.append('<li><a href="/books/?page={}">尾頁</a></li>'.format(total_page))

    page_html = "".join(html_str_list)

    return render(request, "books.html", {"books": all_book, "page_html": page_html})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>書籍列表</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>序號</th>
            <th>id</th>
            <th>書名</th>
        </tr>
        </thead>
        <tbody>
        {% for book in books %}
            <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">
            {{ page_html | safe }}
        </ul>
    </nav>
</div>
</body>
</html>

封裝成通用的模塊

class Page():
    def __init__(self, page_num, total_count, url_prefix, per_page=10, max_page=11):
        """
        :param page_num: 當前頁碼數
        :param total_count: 數據總數
        :param url_prefix: a標籤href的前綴
        :param per_page: 每頁顯示多少條數據
        :param max_page: 頁面上最多顯示幾個頁碼
        """
        self.url_prefix = url_prefix
        self.max_page = max_page

        # 每一頁顯示多少條數據
        # 總共須要多少頁碼來展現
        total_page, m = divmod(total_count, per_page)
        if m:
            total_page += 1
        self.total_page = total_page

        try:
            page_num = int(page_num)
            # 若是輸入的頁碼超過了最大的頁碼數,默認返回最後一頁
            if page_num > total_page:
                page_num = total_page
        except Exception as e:
            # 當輸入的頁碼不是數字的時候,默認返回第一頁的數據
            page_num = 1
        self.page_num = page_num

        # 定義兩個變量保存數據從哪取到哪
        self.data_start = (page_num - 1) * 10
        self.data_end = page_num * 10

        # 頁面上總共展現多少頁碼
        if total_page < self.max_page:
            self.max_page = total_page

        half_max_page = self.max_page // 2
        # 頁面上展現的頁碼從哪開始
        page_start = page_num - half_max_page
        # 頁面上展現的頁碼到哪結束
        page_end = page_num + half_max_page

        # 若是當前頁減一半 比1小
        if page_start <= 1:
            page_start = 1
            page_end = self.max_page

        # 若是當前頁加一半 比總頁碼數還大
        if page_end >= total_page:
            page_end = total_page
            page_start = total_page - self.max_page + 1
        self.page_start = page_start
        self.page_end = page_end

    @property
    def start(self):
        return self.data_start

    @property
    def end(self):
        return self.data_end

    def page_html(self):
        # 拼接分頁的html代碼
        html_str_list = []
        # 加上第一頁
        html_str_list.append('<li><a href="{}?page=1">首頁</a></li>'.format(self.url_prefix))

        # 加上一頁,上一頁就是當前頁減一
        # 判斷,若是第一頁,就沒有上一頁
        if self.page_num <= 1:
            html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
        else:
            html_str_list.append(
                '<li><a href="{}?page={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(self.url_prefix,
                                                                                                   self.page_num - 1))

        for i in range(self.page_start, self.page_end + 1):
            # 若是是當前頁,加一個active樣式類
            if i == self.page_num:
                tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
            else:
                tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
            html_str_list.append(tmp)

        # 加下一頁,下一頁就是當前頁加一
        # 判斷,若是是最後一頁,就沒有下一頁
        if self.page_num >= self.total_page:
            html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>')
        else:
            html_str_list.append(
                '<li><a href="{}?page={}"><span aria-hidden="true">&raquo;</span></a></li>'.format(self.url_prefix,
                                                                                                   self.page_num + 1))

        # 加最後一頁
        html_str_list.append('<li><a href="{}?page={}">尾頁</a></li>'.format(self.url_prefix, self.total_page))

        page_html = "".join(html_str_list)
        return page_html
from django.shortcuts import render

# Create your views here.
from app01 import models

def books(request):
    # 從URL取參數
    page_num = request.GET.get("page")

    # 調用一個類
    from utils.mypage import Page
    page_obj = Page(page_num, total_count, per_page=10, url_prefix="/books/", max_page=11)
    ret = models.Book.objects.all()[page_obj.start: page_obj.end]
    page_html = page_obj.page_html()
    return render(request, "books.html", {"books": ret, "page_html": page_html})

def depts(request):
    # 從URL中取參數
    page_num = request.GET.get("page")
    # 總數據是多少
    total_count = models.Dept.objects.all().count()
    from utils.mypage import Page
    page_obj = Page(page_num, total_count, per_page=10, url_prefix="/depts/", max_page=11)
    ret = models.Dept.objects.all()[page_obj.start: page_obj.end]
    page_html = page_obj.page_html()
    return render(request, "dept.html", {"depts": ret, "page_html": page_html})

完整代碼:https://github.com/qiuxirufeng/page_demo

相關文章
相關標籤/搜索