django学习之自定义分页

一.思路简介:

分页是取部分数据到前端显示,显然前端需要2样东西:
1.当前页和显示页面区间
<1>当前页的获取
可以采用get或post的方法,传递个参数,默认为显示首页
我这里用get传送一个p参数,默认p=1(默认p可能没有传真,所以要判断为空时p=1)
<2>页面区间的获取
首先要知道有多少页,然后推算起始页,结束页,由此再推得上一页和下一页,这些都可以由总数据推算得来,所以要传入总数据进行推算,但是这样有个问题:
如果数据很多,那么传入总数据显然不现实,认真思考则会发现其实我们这里只需要总数据的数量,再进行推算即可,所以相关参数如下:
总页数:总的数据量/每页显示的数量 (不能整除则+1)
(显然我们还要传入每页显示的数量,或者设置个默认值)

        起始页:起始页要分三种情况,我们假设页面为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

        上一页和下一页只要注意下极值即可,即等于首页和尾页就不应该再有值了

2.数据
    数据的获取是基于页面的分割,所以在页面分割中顺便做数据的区间取值
    数据起始位置:(当前页-1)*每页显示的条目数
    数据结束位置:当前页*每页显示的条目数

    前端需要这么多数据,但是他们共同点都是页面分割而来,所以实现就是把页面分割作为一个类对象,再传递给前端

二、代码
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部分:

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部分

{% 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.html

    {% 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)

分页理论上要拿数据(一次拿总数据,一次数据分割),但是为了减少数据读取操作,传入最大条目数,返回取值区间取值(区间取数据,代价更小)
上一篇:ElementUI实现表格分页功能


下一篇:php原生分页类