首页
打开 blueprints/front.py 文件,然后找到 index 视图函数,将代码修改为返回 index.html 模板,代码如下。
@bp.route("/")
def index():
return render_template("front/index.html")
在浏览器中访问 http://127.0.0.1:5000 ,可以看到如图 9-32 所示的页面。

在首页中,左侧帖子列表和右侧板块列表都需要先从视图函数中提取数据,再传给 index.html 模板文件,我们将 index 视图函数代码修改为如下形式。
@bp.route("/")
def index():
posts = PostModel.query.all()
boards = BoardModel.query.all()
context = {
"posts": posts,
"boards": boards
}
return render_template("front/index.html", **context)
接下来在 templates/front/index.html 文件中,循环帖子列表和板块列表。修改后的帖子列表和板块列表代码如下。

上述代码中,首先循环帖子列表,然后把帖子的标题、作者、发表时间以及该帖子评论的数量都显示出来。在板块列表,通过 current_board 参数来表示当前选中的是哪个板块,该参数后续在实现根据板块过滤帖子功能时再加进去。
生成帖子测试数据
在帖子超过一定数量时应该进行分页,但是现在数据库中帖子的数量还太少,我们来生成一些测试数据。这里需要用到 Faker 库来生成随机文字,Faker 库是一个用来生成随机数据的库,可以生成姓名、邮箱、地址以及段落等内容。在 PyCharm 的 Terminal 中通过以下命令安装 Faker 库。
$ pip install faker
更多 Faker 的使用文档请参考 https://faker.readthedocs.io/en/master/index.html。 |
我们把生成帖子测试数据写成命令,在 commands.py 文件中添加以下代码。
from faker import Faker
import random
def create_test_post():
fake = Faker(locale="zh_CN")
author = UserModel.query.first()
boards = BoardModel.query.all()
click.echo("开始生成测试帖子...")
for x in range(98):
title = fake.sentence()
content = fake.paragraph(nb_sentences=10)
random_index = random.randint(0, 4)
board = boards[random_index]
post = PostModel(title=title, content=content, board=board, author=author)
db.session.add(post)
db.session.commit()
click.echo("测试帖子生成成功!")
在 app.py 文件中注册命令,代码如下。
$ app.cli.command("create-test-post")(commands.create_test_post)
打开 PyCharm 的 Terminal,执行 flask create-test-post 命令,即可随机生成 98 篇测试帖子。
使用Flask-Paginate实现分页
在 Flask 项目中使用 Flask-Paginate 插件可以轻松地实现分页,Flask-Paginate 用的是 Bootstrap 样式,正好与现在的项目架构一样,如果要使用其他样式,可以修改 CSS 属性。在 PyCharm 的 Terminal 中输入以下命令安装 Flask-Paginate。
$ pip install flask-paginate
在 config.py 文件的 BaseConfig 中添加 PER_PAGE_COUNT 配置,用来指定一页中展示多少数据,这里设置 10 条,代码如下。
class BaseConfig:
...
PER_PAGE_COUNT = 10
在 blueprints/front.py 的 index 视图函数中,按照当前的页码提取对应的数据,代码如下。
@bp.route("/")
def index():
boards = BoardModel.query.all()
# 获取页码参数
page = request.args.get("page", type=int, default=1)
# 当前 page 下的起始位置
start = (page - 1) * current_app.config.get("PER_PAGE_COUNT")
# 当前 page 下的结束位置
end = start + current_app.config.get("PER_PAGE_COUNT")
# 查询对象
query_obj = PostModel.query.order_by(PostModel.create_time.desc())
# 总共有多少帖子
total = query_obj.count()
# 当前 page 下的帖子列表
posts = query_obj.slice(start, end)
# 分页对象
pagination = Pagination(
bs_version=4, page=page, total=total, outer_window=0,
inner_window=2, alignment="center"
)
context = {
"posts": posts,
"boards": boards,
"pagination": pagination
}
return render_template("front/index.html", **context)
上述代码中,首先从 URL 参数中提取 page,然后计算当前 page 下提取帖子的起始位置和结束位置。接着按照帖子的发布时间进行排序,统计总共有多少帖子,然后使用 start 和 end 提取帖子列表,最后构建分页对象 Pagination, Pagination 中的参数说明如下。
-
bs_version: Bootstrap版本,我们的项目中用的是4,所以这里写4。
-
page:当前的page页码,从1开始。
-
total:所有帖子的总数量。
-
outer_window:页码数量太多,出现省略号后,在省略号外层要显示多少个页码,如这里设置为0,那么就会显示1个页码,总是比设置的多1。
-
inner_window:出现省略号后,当前页码左右两边要显示几个页码。
-
alignment:分页盒子在父盒子内的对齐方式,默认是左对齐,这里修改为中间对齐。
下面在 templates/front/index.html 中的帖子列表的最底部添加 {{ pagination. links }}
,示例代码如下。
<div class="post-group">
<ul class="post-list-group">
<!-- 帖子列表内容 -->
</ul>
{{ pagination.links }}
</div>
在浏览器中重新访问首页,可以看到如图 9-33 所示的帖子分页效果。

过滤帖子
在图 9-33 中,实现了所有板块下的帖子分页功能,本节再来实现帖子按照板块过滤的功能。我们规定板块参数同样用查询字符串的方式传递,在 blueprints/front.py 的 index 视图函数中,将代码修改如下。
@bp.route("/")
def index():
boards = BoardModel.query.all()
# 获取页码参数
page = request.args.get("page", type=int, default=1)
# 新增:获取板块参数
board_id = request.args.get("board_id", type=int, default=0)
# 当前 page 下的起始位置
start = (page - 1) * current_app.config.get("PER_PAGE_COUNT")
# 当前 page 下的结束位置
end = start + current_app.config.get("PER_PAGE_COUNT")
# 查询对象
query_obj = PostModel.query.order_by(PostModel.create_time.desc())
# 新增:过滤帖子
if board_id:
query_obj = query_obj.filter_by(board_id=board_id)
# 总共有多少帖子
total = query_obj.count()
# 当前 page 下的帖子列表
posts = query_obj.slice(start, end)
# 分页对象
pagination = Pagination(
bs_version=4, page=page, total=total, outer_window=0,
inner_window=2, alignment="center"
)
context = {
"posts": posts,
"boards": boards,
"pagination": pagination,
# 新增:当前板块
"current_board": board_id
}
return render_template("front/index.html", **context)
上述代码中,注释中以 “新增:” 开头的是新增的代码。在上述代码中,我们先从 request.args 中获取 board_id 参数,如果获取到了,则让 query_obj 对 board_id 进行过滤后重新赋值,这样得到的 query_obj 就是该板块下所有的帖子。最后为了能在首页中显示当前的板块,将 board_id 赋值给 current_board 传给模板,为了在首页中实现板块过滤,给板块列表加上超链接,修改后的代码如下。
...
{% for board in boards %}
{% if board.id == current_board %}
<a href="{{ url_for('front.index', board_id=board.id) }}" class="list-group-item active">{{ board.name }}</a>
{% else %}
<a href="{{ url_for('front.index', board_id=board.id) }}" class="list-group-item">{{ board.name }}</a>
{% endif %}
{% endfor %}
...
加载以上代码后,在首页中单击右侧的某个板块,就可以实现根据板块过滤帖子的功能了。