Django搭建网络相册:分页

3474 views, 2021/08/12 updated   Go to Comments

正如你想得那样,分页作为一个通用功能,Django 也提供了内置的实现。

Django 把程序员照顾得太好了,严重缩短了大家的工时。

不996怎么升职加薪?

分页器

内置的分页器功能足够强大,配合模型用起来也是极其简单。

修改 views.py 文件:

# /photo/views.py

...
from django.core.paginator import Paginator

def home(request):
    # 已有代码
    photos       = Photo.objects.all()
    # 新增分页代码
    paginator    = Paginator(photos, 5)
    page_number  = request.GET.get('page')
    paged_photos = paginator.get_page(page_number)
    # 将分页器对象传入上下文
    context = {'photos': paged_photos}

    # 后续其他已有代码
    ...

...

你可以看到为了使用分页器,总共修改了四行代码(除去引入模块的语句)。从函数的第二行开始:

  • 将模型的查询集 photos 、以及你期望的每页的图片数量作为参数,实例化分页器 Paginator
  • 从 GET 请求体中获取页码。
  • 根据页码,从分页器中取得对应页码的对象。
  • 分页后的对象传递到模板。

欧了,改前端去。

前端代码

如果你觉得分页器仅仅是将列表做了个切片,那就错了。分页后的数据不仅具有原始查询集(queryset)的迭代功能,还包括了很多分页相关的元数据。

修改 list.html 模板,你就能看出来:

<!-- /templates/photo/list.html -->

...

{% block content %}
    <div class="container py-2">
        <!-- 已有代码 -->
        <div class="row" data-masonry='{"percentPosition": true}'>
            {% for photo in photos %}
            ...
            {% endfor %}
        </div>

        <!-- 新增代码 -->
        <div class="row justify-content-center py-5">
            <span class="step-links paginator">
                {% if photos.has_previous %}
                    <a 
                    href="?page=1" 
                    class="paginator prevnext" >
                        &laquo;
                    </a>
                    <a 
                    href="?page={{ photos.previous_page_number }}" 
                    class="paginator prevnext">
                        {{ photos.previous_page_number }}
                    </a>
                {% endif %}

                    <span class="current">
                        {{ photos.number }}
                    </span>

                {% if photos.has_next %}
                    <a 
                    href="?page={{ photos.next_page_number }}" 
                    class="paginator prevnext">
                        {{ photos.next_page_number }}
                    </a>
                    <a 
                    href="?page={{ photos.paginator.num_pages }}"
                    class="paginator prevnext">
                        &raquo;
                    </a>
                {% endif %}
            </span>
        </div>
    </div>

    ...
{% endblock content %}

<!-- 新增代码 -->
{% block scripts %}
<style>
    .paginator {
        color: white;
        text-align: center;
        text-decoration: none;
    }
    .prevnext {
        font-size: x-large;
    }
    .current {
        font-size: xx-large;
        padding-left: 10px;
        padding-right: 10px;
    }
</style>
{% endblock scripts %}

最主要的改动,就是在页面的底部增加了切换页码的入口。

需要注意的点:

  • 分页后的对象 photos 拥有 previous_page_numbernumberhas_previous 等一系列有关分页的属性,非常方便。(具体作用看属性名就能懂)
  • 超链接用 href="?page={{ photos.next_page_number }}" 给 GET 请求附加了数据,它在后端中通过 request.GET.get('page') 被获取到。
  • 代码末尾用 css 稍微修改了页码的颜色、文字大小等样式。(.current 对应 class="current" 的元素)

又欧了,测试去。

测试

刷新页面看看:

页面底部已经有页码可供选择了。

切换它们,并注意观察浏览器地址栏的变化。

总结

经过几章节的开发,项目的核心功能都具备了:列表、详情、数据存储、批量上传、登录、分页样样不少。

看似真的可以拿去称霸朋友圈了,但还是那个最致命的问题没解决:个人服务器的带宽太有限了,根本支撑不起高清图片的流量。或许可以通过缩略图等手段缓解首页的卡顿,但是细节展示你总要高清大图吧,治标不治本。

解决此问题除了选择更大的带宽外,还可以通过CDN加速、负载均衡、对象存储等手段。

下一章我们将探讨其中一种方案:对象存储(云存储)。

点赞 or 吐槽?评论区见!




本文作者: 杜赛
发布时间: 2021年08月12日 - 09:10
最后更新: 2021年08月12日 - 09:10
转载请保留原文链接及作者