文档章节

Flask开发轻博客(七):分页

AllenOR灵感
 AllenOR灵感
发布于 2017/09/10 01:24
字数 1628
阅读 1
收藏 0

目录

Flask开发轻博客(一):欢迎来到 Flask 的世界

Flask开发轻博客(二):Flask 模板

Flask开发轻博客(三):Flask 的 Web 表单

Flask开发轻博客(四):数据库

Flask开发轻博客(五):用户登录

Flask开发轻博客(六):用户首页和发布博客

Flask开发轻博客(七):分页


分页简介

应用程序看起来比任何时候都要好,但是还是有个问题。我们把所有关注者的 blog 展示在首页上。如果数量超过上千的话会发生些什么?或者上百万?你可以想象得到,处理如此大数据量的列表对象将会及其低效的。

相反,如果我们分组或者分页显示大量的 blog 呢?效率和效果会不会好一些了?

Flask-SQLAlchemy 天生就支持分页。比如如果我们想要得到用户的前三篇文章,我们可以这样做:

pagination = user.posts.paginate(1, PER_PAGE, False).items

paginate 方法能够被任何查询调用。它接受三个参数:

  • 页数,从 1 开始,
  • 每一页的项目数,这里也就是说每一页显示的 blog 数,
  • 错误标志。如果是 True,当请求的范围页超出范围的话,一个 404 错误将会自动地返回到客户端的网页浏览器。如果是 False,返回一个空列表而不是错误。

paginate 返回的值是一个 Pagination 对象。这个对象的 items 成员包含了请求页面项目(本文是指 blog )的列表。在 Pagination 对象中还有其它有帮助的东西,我们将在后面能看到。

现在让我们想想如何在我们的blog首页视图函数中实现分页。我们首先在配置文件中添加一些决定每页显示的 blog 数的配置项(新建文件app/utils.py)

PER_PAGE = 3

在最后的应用程序中我们当然会使用每页显示的 blog 数大于 3,但是测试的时候用小的数量更加方便。

接着,让我们看看不同页的 URLs 是什么样的。我们知道 Flask 路由可以携带参数,因此我们在 URL 后添加一个后缀表示所需的页面

http://127.0.0.1:5000/user/1           <-- page #1 (default)
http://127.0.0.1:5000/user/1/page/1    <-- page #1

这种格式的 URLs 能够轻易地通过在我们的视图函数中附加一个 route 来实现(文件 app/views.py)

from utils import PER_PAGE

@app.route('/user/<int:user_id>', defaults={'page': 1},  methods=["POST", "GET"])
@app.route('/user/<int:user_id>/page/<int:page>', methods=["POST", "GET"])
@login_required
def users(user_id, page):
        form = AboutMeForm()
        user = User.query.filter(User.id == user_id).first()
        if user.id != current_user.id:
                flash("sorry, you can only view your profile!", "error")
                return redirect("/index")

        if not user:
                flash("The user is not exist.")
                redirect("/index")
        blogs = user.posts.paginate(page, PER_PAGE, False).items

        return render_template("user.html",
                                form=form,
                                user=user,
                                blogs=blogs)

我们新的路由需要页面数作为参数,并且声明为一个整型。同样我们也需要在users函数中添加 page 参数,并且我们需要给它一个默认值。

现在我们已经有可用的页面数,我们能够很容易地把它与配置中的PER_PAGE一起传入posts查询。

现在试试输入不同的 URLs,看看分页的效果。但是,需要确保可用的 blog 数要超过三个,这样你就能够看到不止一页了!

页面导航

我们现在需要添加链接允许用户访问下一页以及/或者前一页,幸好这是很容易做的,Flask-SQLAlchemy 为我们做了大部分工作。

我们现在开始在视图函数中做一些小改变。在我们目前的版本中我们按如下方式使用paginate方法

blogs = user.posts.paginate(page, PER_PAGE, False).items

通过上面这样做,我们可以获得返回自 paginatePagination 对象的 items 成员。但是这个对象还有很多其它有用的东西在里面,因此我们还是使用整个对象(文件 app/views.py)

pagination = Post.query.filter_by(
        user_id = current_user.id
        ).order_by(
        db.desc(Post.timestamp) 
        ).paginate(page, PER_PAGE, False)

为了适应这种改变,我们必须修改模板(文件 app/templates/user.html)

{% for blog in pagination.items %}
    <p style="color:#ff6600;">{{ blog.body }}</p>
    <p style="color:#4c4c4c;">{{ blog.timestamp.strftime("%a, %d %b %Y %H:%M:%S") }}</p>
    <hr />
{% endfor %}

这个改变使得模版能够使用完全的 Paginate 对象。我们使用的这个对象的成员有:

  • has_next:如果在目前页后至少还有一页的话,返回 True
  • has_prev:如果在目前页之前至少还有一页的话,返回 True
  • next_num:下一页的页面数
  • prev_num:前一页的页面数

有了这些元素后,我们产生了这些(文件 app/templates/user.html)

{% if pagination %}
    {% for blog in pagination.items %}
    <p style="color:#ff6600;">{{ blog.body }}</p>
    <p style="color:#4c4c4c;">{{ blog.timestamp.strftime("%a, %d %b %Y %H:%M:%S") }}</p>
    <hr />
    {% endfor %}

    {% if pagination.has_prev %} {# 分页的前端展示 #}
    <a href="{{ url_for('users', user_id=current_user.id, page=pagination.prev_num) }}"><< prev</a>
    {% else %}
    << None
    {% endif %} | 
    {% if pagination.has_next %}
    <a href="{{ url_for('users', user_id=current_user.id, page=pagination.next_num) }}">next >></a>
    {% else %}
    None >>
    {% endif %}

{% else %}
    <p style="color:blue;">the guy is so lazy.....</p>
{% endif %}

因此,我们有了两个链接。第一个就是名为 "prev",这个链接使得我们能够访问上一页。第二个就是 "next",它指向下一页。

当我们浏览第一页的时候,我们不希望看到有上一页的链接,因为这时候是不存在前一页。这是很容易被监测的,因为 posts.has_prev 会是 False。我们简单地处理这种情况,当用户浏览首页的时候,上一页会显示出来,但是不会有任何的链接。同样,下一页也是这样的处理方式。

用户信息页

首页上的分页已经完成了。然而,我们在用户信息页上显示了 blog。

改变是跟修改首页一样的。这是我们需要做的列表:

  • 添加一个额外的路由获取页面数的参数
  • 添加一个默认值为 1 的 page 参数到视图函数
  • 用合适的数据库查询与分页代替伪造的 blog
  • 更新模板使用分页对象

下面就是更新后的视图函数(文件 app/views.py)

@app.route('/user/<int:user_id>', defaults={'page': 1},  methods=["POST", "GET"])
@app.route('/user/<int:user_id>/page/<int:page>', methods=["POST", "GET"])
@login_required
def users(user_id, page):
        form = AboutMeForm()
        user = User.query.filter(User.id == user_id).first()
        if user.id != current_user.id:
                flash("sorry, you can only view your profile!", "error")
                return redirect("/index")

        if not user:
                flash("The user is not exist.")
                redirect("/index")
        blogs = user.posts.paginate(page, PER_PAGE, False).items
        pagination = Post.query.filter_by(
                        user_id = current_user.id).order_by(
                        db.desc(Post.timestamp)
                        ).paginate(page, PER_PAGE, False)


        return render_template("user.html",
                                form=form,
                                user=user,
                                blogs=blogs,
                                pagination=pagination)

最终效果图

如果你正确运行上面的程序那么能得到以下的最终效果图。




本文转载自:http://www.jianshu.com/p/5e03cd202728

共有 人打赏支持
AllenOR灵感
粉丝 11
博文 2635
码字总数 83001
作品 0
程序员
私信 提问
《Flask Web开发:基于Python的Web应用开发实战》.PDF

简介 本书不仅适合初级Web开发人员学习阅读,更是Python程序员用来学习高级Web开发技术的优秀参考书。 • 学习Flask应用的基本结构,编写示例应用; • 使用必备的组件,包括模板、数据库、W...

jackmk
2017/08/12
0
0
好书推荐.flask.>

图书封面: 书籍简介: 1. 学习Flask应用的基本结构,编写示例应用; 使用必备的组件,包括模板,数据库,Web表单和电子邮件支持; 使用包和模块构建可伸缩的大型应用; 实现用户认证,角色和个人资...

满满李
2016/06/03
97
0
Flask 插件系列 - Flask-SQLAlchemy

简介 Web 开发中,一个重要的组成部分便是数据库了。Web 程序中最常用的莫过于关系型数据库了,也称 SQL 数据库。另外,文档数据库(如 mongodb)、键值对数据库(如 redis)近几年也逐渐在 ...

funhacks
2017/11/29
0
0
Flask 插件系列 - Flask-MongoEngine

简介 MongoDB 是一个文档型数据库,是 NoSQL (not only SQL) 的一种,具有灵活、易扩展等诸多优点,受到许多开发者的青睐。MongoEngine 是一个用来操作 MongoDB 的 ORM 框架,如果你不知道什...

funhacks
2017/11/29
0
0
Flask框架 —— 从入门到精通

更新日期 :2016 - 2 - 26 有开源网友提醒,故为了可阅读性更新排版。 Hello World 作者背景 应用程序简介 要求 安装 Flask 在 Flask 中的 “Hello, World” 下一步? 模板 回顾 为什么我们需...

水果糖
2016/02/26
402
0

没有更多内容

加载失败,请刷新页面

加载更多

mysql 时间格式化

DATE_FORMAT

1713716445
7分钟前
0
0
聊聊flink的PartitionableListState

序 本文主要研究一下flink的PartitionableListState PartitionableListState flink-runtime_2.11-1.7.0-sources.jar!/org/apache/flink/runtime/state/DefaultOperatorStateBackend.java /*......

go4it
12分钟前
0
0
Micropython教程之TPYBoard开发板制作电子时钟(萝卜学科编程教育)

1.实验目的 1. 学习在PC机系统中扩展简单I/O?接口的方法。 2. 什么是SPI接口。 3. 学习TPYBoard I2C接口的用法。 4. 学习LCD5110接线方法。 5. 设定时钟并将当前时间显示在LCD5110上。 2.所需...

bodasisiter
12分钟前
0
0
js 闭包

闭包,是 Javascript 比较重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是 ECMAScript 规范给的定义,如果没有实战经验,很难从定义去理解它。因此,本文不会对闭包的概念...

MrBoyce
17分钟前
0
0
Java B2B2C o2o多用户商城 springcloud架-企业云架构common-service代码结构分析

当前的分布式微服务云架构平台使用Maven构建,所以common-service的通用服务按照maven构建独立的系统服务,结构如下: particle-commonservice: spring cloud 系统服务根项目,所有服务项目...

itcloud
22分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部