flask入门和进阶六(分页的实现)

将介绍应用程序接受用户的博客帖子,并在/index页面和个人资料页面展示他们

提交博客帖子

主页需要一个 表单,用户在此可以写新帖子。首先,建立一个表单类: app/forms.py:博客提交表单

接着,将上述表单添加到应用程序主页的模板中:
app/templates/index.html:index模板中帖子提交表单

这个模板的更改与以前的表单处理方式类似。

最后,在视图函数 index() 中添加上述表单的创建和处理:修改代码
app/routes.py:在视图函数中的帖子提交表单

逐一查看视图函数中的更改:

  1. 导入 PostPostForm类;
  2. GET请求外,关联到两个路由的视图函数index()都接受POST请求,因为这个视图函数现在将接收表单数据;
  3. 表单处理逻辑将一个新Post记录 插入数据库;
  4. 模板接收 form对象作为一个附加参数,以便它呈现文本字段。

在继续之前,我想提一些处理Web表单相关的重要事项。注意,在我处理表单数据后,通过发出一个重定向到主页来结束请求。我可以轻松地跳过重定向,并允许函数继续向下进入模板渲染部分,因为这已经是index()视图函数的功能了。

所以,为什么要重定向?标准做法是通过重定向来响应一个由Web表单提交生成的POST请求。这有助于缓解一个在Web浏览器如何实现刷新命令的烦恼。当点击 刷新键时,所有Web浏览器都会重新发出最后一个请求。如果带有表单提交的POST请求返回常规响应,那么刷新将重新提交表单。因为这是意料之外的,浏览器将要求用户确认重复提交,但大多数用户将无法理解浏览器询问的内容。但是,如果POST请求用重定向来回答请求,则浏览器现在指示发送一个GET请求以获取重定向中指示的页面,因此,现在最后一个请求不再是POST请求,刷新命令可以更可预测的方式工作。

这个简单的技巧称为:Post/Redirect/Get模式当用户在提交Web表单后,无意中刷新页面时,它可以避免插入重复的帖子。

 

显示博客的帖子

应该记得,之前创建了一些虚假博客帖子,在主页上显示了很长时间了。这些虚拟对象在`index()`视图函数中显示创建为一个简单的Python列表:

但是,现在User模型中我有followed_posts()方法,它返回给定用户想看的帖子的查询。所以,现在可用真正的帖子替换“假”帖子:

app/routes.py:在主页显示真实的帖子

User类的followed_posts()方法返回一个SQLAlchemy查询对象,这个对象配置为 从数据库中获取用户感兴趣的帖子。在这个查询中调用all()方法会触发其执行,返回值为一个所有结果集的列表。所以最终得到的结构 跟之前使用的“假”帖子非常相似。正因如此,模板就无须更改了。

对外开放页面

创建一个新的页面,称之为“‘explore’”这个页面像主页一样工作,但不会仅显示来之所关注用户的帖子,而是显示来自所有用户的全局帖子流,下面是新的explore()视图函数

可注意到,这个视图函数有些奇怪。render_template()调用引用了index.html模板,它是应用程序的主页使用的模板。由于这个页面 跟主页面非常相似,因此重用index.html模块。不过,与主页面有一个区别是 在/explore页面中不需要一个写博客帖子的表单,所以在这个视图函数中,没有在模板中调用 包含form的参数。

为了防止index.html模板在呈现不存在的Web表单时崩溃,将添加一个条件,只有在定义时才呈现表单(即传入表单参数后才会呈现):app/templates/index.html:让博客帖子提交表单 可选

还需在导航栏添加指向这个新页面的连接

app/templates/base.html

记得在第6章介绍的_post.html子模板,用于在用户个人资料页面中呈现博客帖子。这是一个包含在用户个人资料页面模板中的小模板,是独立的,因此也可以从其他模板中引用。现在对它进行一些改进,即 将博客帖子作者的用户名显示为链接

子模板需要一个存在的名为 post 的变量,才能完美地工作,这是在 index模板中 循环变量的命名方式

通过上述这些微小的变化,应用程序的可用性得到显著改善。现在,用户可访问 /explore页 阅读来自未知用户的博客帖子,并根据这些帖子找到要关注的新用户,只需单击用户名就可访问 个人资料页面。

flask run 运行程序,登录susan2018、belen、john发几个帖子,效果:

博客帖子的分页

 

现在应用程序看起来比以前更好,但是在主页显示所有关注的帖子很快将变成一个问题。如果用户有1000个关注帖子会怎么样?如果是100万呢?可以想象,管理如此庞大的帖子列表将很缓慢且效率低下。、

为解决这个问题,我将对帖子列表进行分页。这意味着,最初将一次只显示有限数量的帖子,并包含用于浏览整个帖子列表的链接Flask-SQLAlchemy本身支持使用paginate()查询方法进行分页。例如,如果想获得用户的前20个帖子,可以用如下代码替换all()终止查询:

paginate()方法可以在Flask_SQLAlchemy的任何查询对象上调用。它有3个参数:

在最终的应用程序中,会使用大于3个博客的数字,但对于测试,使用小数字就可以

接下来需要将页码合并到应用程序的url中,常见的方法是使用查询字符串参数来指定可选的页码,例如

通过上述更改,两个路由确定要显示的页码,可以是page查询字符串参数,或默认值1.然后使用paginate()方法取得所需结果的页面。通过app.config对象的POST_PRE_PAGE配置项决定了要访问页码的大小

注意,这些更改很容易,以及 每次更改代码的影响程度如何。编写应用程序的每个部分时,而不对其他部分如何工作做任何假设,这使我能够编写更易于扩展和测试的模块化、健壮的应用程序,并且不太可能出现故障 或bug。

运行程序,测试上述所编写的分页支持。首先,确保3篇以上的帖子。这在 /explore页面很容易看到,这个页面显示所有用户的帖子。目前将只会看到最近的3篇帖子。若要查询下一个3篇帖子,可在浏览器地址栏输入:http://localhost:5000/explore?page=2

页面导航(上一页,下一页)

 

下一个要更改的是在帖子列表底部添加链接,允许用户导航到下一页或上一页。还记得 调用paginate()方法的返回值是一个Flask-SQLAlchemyPagination类的一个对象?目前为止,我们已经使用了这个对象的items属性,它包含为所选页面检索的项目列表。但是 这个对象还具有一些在构建分页链接时有用的前提属性:

1,has_next:如果当前页面后面至少还有一页,则为True

2,has_prev:如果当前页面之前还有一页。则为true

3,next_num:下一页的页码

4,prev_num:上一页的页码

通过上述4个属性,可生成下一个和上一个页面链接,并将它们传递给模板进行渲染:
app/routes.py:下一页和上一页链接

#...
def index():
	#...
    page = request.args.get('page', 1, type=int)
    posts = current_user.followed_posts().paginate(page, app.config['POSTS_PER_PAGE'], False)
    next_url = url_for('index', page=posts.next_num) if posts.has_next else None
    prev_url = url_for('index', page=posts.prev_num) if posts.has_prev else None
    return render_template('index.html', title='Home Page', form=form, posts=posts.items, next_url=next_url, prev_url=prev_url)

@app.route('/explore')
@login_required
def explore():
    page = request.args.get('page', 1, type=int)
    posts = Post.query.order_by(Post.timestamp.desc()).paginate(page, app.config['POSTS_PER_PAGE'], False)
    next_url = url_for('explore', page=posts.next_num) if posts.has_next else None
    prev_url = url_for('explore', page=posts.prev_num) if posts.has_prev else None
    return render_template('index.html', title='Explore', posts=posts.items, next_url=next_url, prev_url=prev_url)

上述连个视图函数的next_url和prev_url只有在该方向上有页面时,才会设置为由url_for()返回一个url。如果当前页面位于帖子集合的一端,则Pagination对象的has_nexthas_prev属性将是False,并在这种情况下,该方向上的链接将被设置为None

url_for()函数有一个有趣的方面(之前未讨论过)是 你能够向它添加任何关键字参数,如果这些参数的名字没有直接在URL中引用,那么Flask会将它们作为查询参数包含在URL中。

 

参考:https://blog.csdn.net/weixin_38256474/article/details/81672110

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值