django學習之自定義分頁

一.思路簡介:css

分頁是取部分數據到前端顯示,顯然前端須要2樣東西:
1.當前頁和顯示頁面區間
<1>當前頁的獲取
能夠採用get或post的方法,傳遞個參數,默認爲顯示首頁
我這裏用get傳送一個p參數,默認p=1(默認p可能沒有傳真,因此要判斷爲空時p=1)
<2>頁面區間的獲取
首先要知道有多少頁,而後推算起始頁,結束頁,由此再推得上一頁和下一頁,這些均可以由總數據推算得來,因此要傳入總數據進行推算,可是這樣有個問題:
若是數據不少,那麼傳入總數據顯然不現實,認真思考則會發現其實咱們這裏只須要總數據的數量,再進行推算便可,因此相關參數以下:
總頁數:總的數據量/每頁顯示的數量 (不能整除則+1)
(顯然咱們還要傳入每頁顯示的數量,或者設置個默認值)html

起始頁:起始頁要分三種狀況,咱們假設頁面爲70頁,一次拿出7頁擺放(這裏我姑且叫顯示頁面),當前頁在中間,那麼數據相似:1-7,2-8...64-70,那麼:
當前頁爲[1,3]時,起始頁爲1
當前頁爲[68,70],起始頁爲64
其餘狀況,起始頁與當前頁的間距是相等的,即爲顯示頁面的一半,因此可得:
當前頁<顯示頁面的/2時,起始頁=1
最大頁-當前頁<顯示頁面的/2時,起始頁=最大頁-顯示頁面+1(用70-7+1=64推)
其餘狀況:起始頁=當前頁-顯示頁面/2+1前端

結束頁:結束頁可由起始頁推得,由於整個顯示區間是固定的
結束頁=起始頁+顯示頁面-1
上一頁和下一頁只要注意下極值便可,即等於首頁和尾頁就不該該再有值了python

2.數據
數據的獲取是基於頁面的分割,因此在頁面分割中順便作數據的區間取值
數據起始位置:(當前頁-1)x 每頁顯示的條目數
數據結束位置:當前頁 x每頁顯示的條目數django

前端須要這麼多數據,可是他們共同點都是頁面分割而來,因此實現就是把頁面分割做爲一個類對象,再傳遞給前端bootstrap


2、代碼
pager.py

``

class Pagination(object):

def __init__(self, dataCount, currentPage=1, cowCount=10, perPageCount=10):
    self.totalCount = dataCount
    self.perPageCount=perPageCount
    self.cowCount=cowCount
    if currentPage <= 0:
        self.currentPage=1
    elif currentPage>self.max_page:
        self.currentPage=self.max_page
    else:
        self.currentPage=currentPage
@property
def max_page(self):
    a,b=divmod(self.totalCount,self.perPageCount)
    if b==0:
        return a
    else:
        return a+1

@property
def start_page(self):
    # 1-10 2-11 3-12
    # 1-7 2-8 3-9
    # 假設當前頁在中間,則有:
    step=int(self.cowCount/2)
    if self.currentPage<=step:
        return 1
    elif self.max_page-self.currentPage<step:
        return self.max_page-self.cowCount+1
    else:
        return self.currentPage-step+1

@property
def end_page(self):
    return self.start_page+self.cowCount-1
@property
# 模板語言的循環語句只有for in結構,只能返回列表供模板頁面使用
def page_range(self):
    return range(self.start_page, self.end_page+1)

@property
def next_page(self):
    if self.currentPage<self.max_page:
        return self.currentPage+1
    else:
        return "out"

@property
def prev_page(self):
    if self.currentPage > 1:
        return self.currentPage-1
    else:
        return "out"

def data_start(self):
    return (self.currentPage-1)*self.perPageCount

def data_end(self):
    return self.currentPage * self.perPageCount

view部分:app

from cdnpanel.pager import Pagination

def test(request):

    dataCount=Domain.objects.filter(User__username="linzb").count()
    page_v=request.GET.get("p")
    if page_v :
        currentPage = int(page_v)
    else:
        currentPage = 0
    page_obj=Pagination(dataCount,currentPage,8)
    data_start=page_obj.data_start()
    data_end=page_obj.data_end()
    # data_obj=Domain.objects.filter(id__gte=98,id__lte=105)
    data_obj=Domain.objects.all()[data_start:data_end]
    print(page_obj.start_page,page_obj.end_page)
    return render(request, 'test.html',{"data":data_obj,"page_obj":page_obj,"url":"test"})

test.html部分dom

{% load static %}
<link rel="stylesheet" href="{% static 'plugin/bootstrap/css/bootstrap.min.css' %}">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
            <tbody>
                {% for item in data %}
                    <tr data_id="{{ item.id }}">
                   <p> <td>{{ item.domain }}</td></p>
                    <p><td>{{ item.src }}</td></p>
                    </tr>
                {% endfor %}
            </tbody>

    {% if page_obj.prev_page == "out" %}
        <a href="#">上一頁</a>
    {% else %}
        <a href="/{{ url }}?p={{ page_obj.prev_page }}" class="btn">上一頁</a>
    {% endif %}
    {% for a_ele in page_obj.page_range %}
        {% if a_ele == page_obj.currentPage %}
            <a href="/{{url }}?p={{ a_ele }}" class="btn btn-default btn-xs" style="size:30px;font-size:30px;color: red">{{ a_ele }}</a>
        {% else %}
            <a href="/{{url }}?p={{ a_ele }}" class="btn" >{{ a_ele }}</a>
        {% endif %}
    {% endfor %}
        {% if page_obj.next_page == "out" %}
        <a href="#" class="btn">下一頁</a>
    {% else %}
        <a href="/{{ url }}?p={{ page_obj.next_page }}" class="btn">下一頁</a>
    {% endif %}
    {{ page_obj.currentPage }}/{{ page_obj.max_page }}

把前端分頁部分獨立出來(之後能夠作通用模板)
pager.htmlide

{% if page_obj.prev_page == "out" %}
        <a href="#">上一頁</a>
    {% else %}
        <a href="/{{ url }}?p={{ page_obj.prev_page }}" class="btn">上一頁</a>
    {% endif %}
    {% for a_ele in page_obj.page_range %}
        {% if a_ele == page_obj.currentPage %}
            <a href="/{{url }}?p={{ a_ele }}" class="btn btn-default btn-xs" style="size:30px;font-size:30px;color: red">{{ a_ele }}</a>
        {% else %}
            <a href="/{{url }}?p={{ a_ele }}" class="btn" >{{ a_ele }}</a>
        {% endif %}
    {% endfor %}
        {% if page_obj.next_page == "out" %}
        <a href="#" class="btn">下一頁</a>
    {% else %}
        <a href="/{{ url }}?p={{ page_obj.next_page }}" class="btn">下一頁</a>
    {% endif %}
    {{ page_obj.currentPage }}/{{ page_obj.max_page }}

在上一篇中進行應用:
把view中index部分的代碼改成函數

def index(request):
    if request.COOKIES.get("is_login"):
        # username = request.COOKIES.get('username')
        # data = Domain.objects.filter(User__username=username)
        # engine = Proxy.objects.all()
        # user = User.objects.all()
        # return render(request, 'index.html', {'data': data, "engine": engine, "user": user})
        username = request.COOKIES.get('username')
        dataCount = Domain.objects.filter(User__username=username).count()
        page_v = request.GET.get("p")
        if page_v:
            currentPage = int(page_v)
        else:
            currentPage = 0
        page_obj = Pagination(dataCount, currentPage, 7)
        data_start = page_obj.data_start()
        data_end = page_obj.data_end()
        data_obj = Domain.objects.all()[data_start:data_end]
        engine = Proxy.objects.all()
        user = User.objects.all()
        return render(request, 'index.html', {'data': data_obj, "engine": engine, "user": user,"page_obj":page_obj,"url":"index"})
    else:
        return redirect('/login')

在index.html中引用:

{% include 'pager.html' %}
在原來的代碼中加入此句

效果圖:
django學習之自定義分頁

debug:

1.python manage.py migrate報錯 
django.db.utils.OperationalError: (1829, "Cannot drop column 'id': needed in a foreign key constraint 'cdnpanel_domain_m_domain_id_63a1eb5a_fk_cdnpanel_domain_id' of table
'cdnpanel_domain_m'")
緣由:django 建立外鍵也會爲其建立索引,當被約束的表結構出現變動便會報錯
解決:刪除對應外鍵索引便可
語法: alter table TB drop foreign key  INDEX_NAME;

2.django從新生成表報錯找不到錯誤緣由(如有數據先備份)

    可嘗試:<1>rm -rf migrations/__pycache__/
            <2>delete from django_migrations where app=‘要刪的app名’;

    實在不行:
            刪掉migrations下除了__init__.py之外全部文件(結合<1><2>)

3.    return range(self.start_page, self.end_page)
TypeError: 'float' object cannot be interpreted as an integer
    緣由:函數返回值中self.perPageCount/2可能爲小數
    解決:return self.currentPage-int(self.perPageCount/2)

分頁理論上要拿數據(一次拿總數據,一次數據分割),可是爲了減小數據讀取操做,傳入最大條目數,返回取值區間取值(區間取數據,代價更小)
相關文章
相關標籤/搜索