顺之利

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

分页的原理

Django是一个非常全面的Web框架,也预置了分页的功能,这点稍后介绍。然而,我并不想按照Django给的分页功能来做。学习一个东西最好学习它的本质。分页的原理其实很简单,就是根据你传入的参数从数据库获取一部分的数据来展示。比如按照5篇文章来分页,每次就从数据库取5条数据,然后返回给前端展示即可。

 

手动分页

models的配置,并且一经使用了makemigrations和migrate同步了数据库中的表

class Host(models.Model):
    name = models.CharField(max_length=10)
    ip = models.GenericIPAddressField()

    def __str__(self):
        return self.name
models

 

view的设置

def batch(request, page):
    page = transfer2int(page, 1)
    count = Host.objects.count()

    per_item = transfer2int(request.COOKIES.get("pageNum", 30), 30)
    print("每页的大小", per_item)

    # 总页数
    page_num = math.ceil(count/per_item)

    if page > page_num:
        page = page_num
    elif page <= 0:
        page = 1

    # 本页的开始
    start = (page - 1) * per_item
    end = min(page * per_item, count)

    hosts = Host.objects.all()[start:end]
    print("page", page)
    print(hosts)
    if page_num <= 11:
        startIndex = 1
        endIndex = page_num
    else:
        if page <6:
            startIndex = 1
            endIndex = 11
        elif page + 5 > page_num:
            endIndex = page_num
            startIndex = page_num - 10
        else:
            startIndex = page - 5
            endIndex = page + 5
    return render(request, "batch.html", {"hosts": hosts,
                                          "count": count,
                                          "bars": range(startIndex, endIndex+1),
                                          "page_num": page_num,
                                          "page": page}
view的配置
page是从url出接收到的页码,也就是第几页,函数transfer2int是为了将字符串page转成数值型
def transfer2int(arg, default):
    try:
        result = int(arg)
    except ValueError as e:
        result = default
    return result
transfer2int
count是表中的总记录数
per_item是每页有多少条记录
page_num是总页数
hosts 是查询好的数据记录信息

为了页面显示友好,也可以展示 页码条,当前是总共展示11个选择


页面配置信息
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>分页</title>
    <script type="text/javascript" src="{% static 'js/jquery-3.1.1.js' %}"></script>
    <script type="text/javascript" src="{% static 'js/jquery.cookie.js' %}"></script>
    <style type="text/css">
        table, td{
            border: solid 1px blueviolet;
        }
        #paging a{
            background-color: green;
            border: white solid 1px;
            text-decoration: none;
            color: white;
        }
        #paging a.selected{
            color: red;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <td>主机名</td>
        <td>IP</td>
    </tr>
    {% for host in hosts %}
        <tr>
            <td>{{ host.name }}</td>
            <td>{{ host.ip }}</td>
        </tr>
    {% endfor %}
</table>
<div>总条数{{ count }}</div>
<select id="pageNum" onchange="changePageNum();">
    <option value="10">10</option>
    <option value="20">20</option>
    <option value="30">30</option>
    <option value="50">50</option>
    <option value="100">100</option>
</select>
<div id="paging">
    {% if page_num == 1 %}
        <a href="/shop/batch/1/">1</a>
    {% else %}
        {% if page > 1 %}
            <a href="/shop/batch/1/">首页</a>
        {% endif %}
        {% if page >= 2 %}
            <a href="/shop/batch/{{ page|add:-1 }}/">上一页</a>
        {% endif %}
        {% for bar in bars %}
            {% if page == bar %}
                <a href="/shop/batch/{{ bar }}/" class="selected">{{ bar }}</a>
            {% else %}
                <a href="/shop/batch/{{ bar }}/">{{ bar }}</a>
            {% endif %}
        {% endfor %}
        {% if page < page_num %}
            <a href="/shop/batch/{{ page|add:1 }}/">下一页</a>
            <a href="/shop/batch/{{ page_num }}/">尾页</a>
        {% endif %}
    {% endif %}
</div>

<script type="text/javascript">
    var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
    $(function () {
        var pageNum = $.cookie("pageNum");
        if (pageNum>0){
            $("#pageNum").val(pageNum);
        } else {
            $("#pageNum").val(30);
        }
    });
</script>
</body>
</html>
template
原来我使用了ajax,在本例中没有使用。ajax在下篇随笔中会说明。

Django分页

django分页的关键使用了

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

关键是view中的编写
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def batch2(request):
    page = transfer2int(request.GET.get('page'), 1)
    count = Host.objects.count()

    per_item = 10
    print("每页的大小", per_item)

    all_host = Host.objects.all()
    paginator = Paginator(all_host, per_item)  # Show 25 contacts per page
    try:
        hosts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        hosts = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        hosts = paginator.page(paginator.num_pages)

    return render(request, "batch2.html", {"hosts":hosts})
View Code

页面如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>django分页</title>
</head>
<body>

{% for host in hosts %}
    {{ host.name }}<br>
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if hosts.has_previous %}
            <a href="?page={{ hosts.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ hosts.number }} of {{ hosts.paginator.num_pages }}.
        </span>

        {% if hosts.has_next %}
            <a href="?page={{ hosts.next_page_number }}">next</a>
        {% endif %}
    </span>
</div>

</body>
</html>
页面

 

还有一个问题没有解决哦,因为肯定有朋友会问,如果一个列表有100000个item, 我们想要实现每页40个,那么,当将我们请求该列表时,paginator 在分页过程中,请求数据库是取40个,还是取100000啊!显然,paginator 是不可能取100000的啦。paginator 巧妙的利用了Django延迟获取数据的特性,因此,paginator 每次取数据都是只取每页的数据的(也就是上例中的40个),所以是不会有性能 影响 的哦。

 

官方文档  https://docs.djangoproject.com/en/1.10/topics/pagination/

posted on 2017-02-09 17:50  顺之利  阅读(554)  评论(0编辑  收藏  举报