Flask博客实战 - 实现文章列表页及详情页
在本系统中:
实现了分类列表页视图/category/int:cateid并对应的catelist.html模板
使用filter方法根据分类ID查询对应文章并分页展示
实现了文章详情页视图/category/int:cateid/int:postid并对应的detail.html模板
通过上一篇/下一篇逻辑展示了动态导航功能
在导航菜单中增加了分类路径的URL
实现分类列表页
在设计数据库字段结构时,我们将分类与文章归类为一对多的关系结构.这样每个分类下会有多个文章.由于上一节已实现这一点,本节的目标就是实现每个分类对应的动态列表页面.
在app/blog/views.py中实现分类页视图
@bp.route('/category/<int:cate_id>')
def cates(cate_id):
# 分类页
cate = Category.query.get(cate_id)
page = request.args.get('page', 1, type=int)
pagination = Post.query.filter(Post.category_id==cate_id).paginate(page, per_page=10, error_out=False)
post_list = pagination.items
return render_template('cate_list.html', cate=cate, post_list=post_list, cate_id=cate_id, pagination=pagination)
这个函数的逻辑也是在之前开发管理后台功能时反复进行过实现。在这里我们采用了基于filter的方法,并根据传入的url中的分类主键id来查询对应的分类数据集,并对获取的结果进行分页处理。
生成该app/blog/templates目录下的cate_list.html模版文件
{% extends 'base.html' %}
{% block title %}{{ cate.name }}{% endblock title %}
{% block hero %}{% endblock hero %}
{% block box %}
<div class="columns">
<div class="column is-9" style="border-right:solid 1px #eee ;">
<div class="box is-shadowless has-background-light">
{% block breadcrumb %}
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
<ul>
<li><a href="/">首页</a></li>
<li class="is-active"><a href="#" aria-current="page">{{ cate.name }}</a></li>
</ul>
</nav>
{% endblock breadcrumb %}
</div>
{% block cate_box %}
{% for post in post_list %}
<div class="pl-2">
<h1 class="is-size-4">
<a href="{{ url_for('blog.detail', cate_id=post.category.id, post_id=post.id) }}">{{ post.title }}</a>
</h1>
<p class="has-text-grey-light is-size-6 mt-1">
<span class="icon"><i class="mdi mdi-clipboard-text-clock-outline"></i></span>{{ post.add_date }}
<span class="icon"><i class="mdi mdi-shape-outline"></i></span>{{ post.category.name }}
<span class="icon"><i class="mdi mdi-tag-heart-outline"></i></span>{{ post.tags|join(',') }}
</p>
<div class="has-text-grey mt-1">{{ post.desc }}</div>
</div>
<div class=" dropdown-divider mb-3"></div>
{% endfor %}
{% block pagination %}
<nav class="pagination is-small" role="navigation" aria-label="pagination">
{% if pagination.has_prev %}
<a href="{{ url_for('blog.cates', cate_id=cate.id ) }}?page={{ pagination.prev_num }}" class="pagination-previous" title="This is the first page">Previous</a>
{% endif %}
{% if pagination.has_next %}
<a href="{{ url_for('blog.cates', cate_id=cate.id) }}?page={{ pagination.next_num }}" class="pagination-next">Next page</a>
{% endif %}
<ul class="pagination-list">
{% for page in pagination.iter_pages() %}
{% if page %}
{% if page != pagination.page %}
<li>
<a href="{{ url_for('blog.cates', cate_id=cate.id) }}?page={{ page }}" class="pagination-link" aria-label="Page 1" aria-current="page">{{ page }}</a>
</li>
{% else %}
<li>
<a class="pagination-link is-current" aria-label="Page 1" aria-current="page">{{ page }}</a>
</li>
{% endif %}
{% else %}
<span class=pagination-ellipsis>…</span>
{% endif %}
{% endfor %}
</ul>
</nav>
{% endblock pagination %}
{% endblock cate_box %}
</div>
<div class="column">
asdas
</div>
</div>
{% endblock box %}
在该模板中,我们从刚才的视图中获取了返回的数据.此外,在继承base.html的基础上,我们实现了具有'一目了然'功能的样式表.
- 最终样式

实现文章详情页
在app/blog/views.py中实现文章详情页视图
@bp.route('/category/<int:cate_id>/<int:post_id>')
def detail(cate_id, post_id):
# 详情页
cate = Category.query.get(cate_id)
post = Post.query.get_or_404(post_id)
# 上一篇
prev_post = Post.query.filter(Post.id < post_id).order_by(-Post.id).first()
# 下一篇
next_post = Post.query.filter(Post.id > post_id).order_by(Post.id).first()
return render_template('detail.html', cate=cate, post=post, prev_post=prev_post, next_post=next_post)
这段代码不仅实现了文章详情页,还实现了上一篇及下一篇的功能!
经由url路径,我们依次获取了分类相关的cate_id标识符以及当前文章的post_id主键值。随后基于这两个关键参数信息,我们成功地检索到对应的分类信息及其相关文章内容。代码实现见下文
cate = Category.query.get(cate_id)
post = Post.query.get_or_404(post_id)
在本系统中,开发团队综合完成了相关文章中的前一篇及后一篇功能,并通过当前文章的id来判断筛选出上一篇和下一篇内容.代码如下:
# 上一篇
prev_post = Post.query.filter(Post.id < post_id).order_by(-Post.id).first()
# 下一篇
next_post = Post.query.filter(Post.id > post_id).order_by(Post.id).first()
在app/blog/templates/中创建一个detail.html的模板文件
{% extends 'cate_list.html' %}
{% block title %}
{{ post.title }}
{% endblock title %}
{% block breadcrumb %}
<nav class="breadcrumb is-small" aria-label="breadcrumbs">
<ul>
<li><a href="/">首页</a></li>
<li><a href="{{ url_for('blog.cates', cate_id=cate.id) }}">{{ cate.name }}</a></li>
<li class="is-active"><a href="#" aria-current="page">{{ post.title }}</a></li>
</ul>
</nav>
{% endblock breadcrumb %}
{% block cate_box %}
<div class="pl-2">
<h1 class="is-size-3">
{{ post.title }}
</h1>
<p class="has-text-grey-light is-size-6 mt-1">
<span class="icon"><i class="mdi mdi-clipboard-text-clock-outline"></i></span>{{ post.add_date }}
<span class="icon"><i class="mdi mdi-shape-outline"></i></span>{{ post.category.name }}
<span class="icon"><i class="mdi mdi-tag-heart-outline"></i></span>{{ post.tags|join(',') }}
</p>
<div class="content has-text-grey mt-1">{{ post.content|safe }}</div>
</div>
<hr>
<div class="level">
<div class="level-left">
{% if prev_post %}
上一篇:<a href="{{ url_for('blog.detail', cate_id=prev_post.category.id, post_id=prev_post.id) }}">{{ prev_post.title }}</a>
{% endif %}
</div>
<div class="level-right">
{% if next_post %}
下一篇:<a href="{{ url_for('blog.detail', cate_id=next_post.category.id, post_id=next_post.id) }}">{{ next_post.title }}</a>
{% endif %}
</div>
</div>
{% endblock cate_box %}
增加导航菜单中的url
路径: app/blog/templates/base.html
{% for cate in categorys %}
<b-navbar-item
{% if cate.id == cate_id %}class="has-text-primary"{% endif %}
href="{{ url_for('blog.cates', cate_id=cate.id) }}">
{{ cate.name }}
</b-navbar-item>
{% endfor %}
首页文章url完善
路径: app/blog/templates/base.html
{% for post in posts %}
<div class="column is-4-fullhd is-6-desk">
<div class="card">
<div class="card-image">
<figure class="image is-4by5">
<img src="{{ post.img }}" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="content">
<p class="title is-4"><a
href="{{ url_for('blog.detail', cate_id=post.category.id, post_id=post.id) }}">{{ post.title}}</a> </p>
<p class="has-text-grey subtitle is-size-6">
{{ post.desc }}
</p>
<time class="has-text-grey" datetime="{{ post.add_date }}">{{ post.add_date }}</time>
</div>
</div>
</div>
</div>
{% endfor %}
