Flask博客实战 - 实现侧边栏文章归档及标签
该教程详细介绍了如何在博客应用中实现侧边栏模块的功能设计与开发过程。主要包括以下核心内容:
侧边栏模块设计:通过当前项目的布局,在blog应用中实现搜索、最新文章、文章归档和标签等四个常见模块的功能展示。
文章归档功能:通过Post.query.filter()方法按月查询并返回对应的文章数据,并通过url_for('blog.archive', date=date)生成归档页面链接。
标签功能:直接查询所有标签并为每个标签添加样式属性以配合前端显示不同颜色。
模板整合:在cate_list.html模板中新增两个侧边栏块分别展示归档和标签信息,并结合正则表达式进行年月匹配筛选数据。
整篇文章通过精炼的语言概括了实现细节和技术要点,适合开发者快速理解和掌握相关功能的开发流程与技术方案。
通常在博客网站布局中会设置有侧边栏。常见设置包括搜索功能、最新文章列表、分类索引以及标签聚合等功能!本教程将指导您完成这一系列功能。
基于当前项目的设置,“侧边栏仅用于 blog 应用的列表页和详情页显示”。该视图已通过 blog 蓝图实现绑定,请问是否正确?因此,在左侧边栏时我们只需关注该应用即可!
- 最终的效果

实现文章归档功能
在app/blog/views.py中通过博客的蓝图注入上下文,代码如下
@bp.context_processor
def inject_archive():
# 文章归档日期注入上下文
posts = Post.query.order_by(Post.add_date)
dates = set([post.add_date.strftime("%Y年%m月") for post in posts])
# 标签
tags = Tag.query.all()
for tag in tags:
tag.style = ['is-success', 'is-danger', 'is-black', 'is-light', 'is-primary', 'is-link', 'is-info', 'is-warning']
return dict(dates=dates, tags=tags)
代码如下
posts = Post.query.order_by(Post.add_date)
dates = set([post.add_date.strftime("%Y年%m月") for post in posts])
随后从数据库中获取所有文章,并按发布时间降序排列(新发布的内容排在前面)。接着提取每篇文章对应的年月份信息,并利用strftime方法将其格式化为所需的月份表示形式。随后去除重复项以确保数据唯一性,并将处理后的结果反馈给后续流程。
实现文章归档的详情视图
@bp.route('/category/<string:date>')
def archive(date):
# 归档页
import re
# 正则匹配年月
regex = re.compile(r'\d{4}|\d{2}')
dates = regex.findall(date)
from sqlalchemy import extract, and_, or_
page = request.args.get('page', 1, type=int)
# 根据年月获取数据
archive_posts = Post.query.filter(and_(extract('year', Post.add_date) == int(dates[0]), extract('month', Post.add_date) == int(dates[1])))
# 对数据进行分页
pagination = archive_posts.paginate(page, per_page=10, error_out=False)
return render_template('archive.html', post_list=pagination.items, pagination=pagination, date=date)
该系统会将输入的url参数解析为日期对象。然后利用正则表达式模式识别并分离出年份与月份字段。代码如下:
import re
# 正则匹配年月
regex = re.compile(r'\d{4}|\d{2}')
dates = regex.findall(date)
下边这段代码采用了sqlalchemy支持extract和and_这两个方法(examples: extract用于提取某个字段的具体值(and_实现了两个条件之间的逻辑与关系))然后根据通过正则表达式获取到的年月信息进行精确匹配筛选出当月的文章内容!
from sqlalchemy import extract, and_, or_
archive_posts = Post.query.filter(and_(extract('year', Post.add_date) == int(dates[0]), extract('month', Post.add_date) == int(dates[1])))
其他代码都是在之前的章节中多次使用,大家自行理解!
生成归档页面的模板文件模板,并将archive.html文件放置于/app/blog/templates/目录下,请参考以下代码:
{% extends 'cate_list.html' %}
{% block title %}{{ date }}的文章归档 {% endblock title %}
{% block hero %}{% endblock hero %}
{% 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">{{ date }}的归档</a></li>
</ul>
</nav>
{% endblock breadcrumb %}
{% block pagination %}
<nav class="pagination is-small" role="navigation" aria-label="pagination">
{% if pagination.has_prev %}
<a href="{{ url_for('blog.archive', date=date ) }}?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.archive', date=date) }}?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.archive', date=date) }}?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 %}
实现文章标签功能
该函数的具体实现细节见下文链接:函数中的代码如下
# 标签
tags = Tag.query.all()
for tag in tags:
tag.style = ['is-success', 'is-danger', 'is-black', 'is-light', 'is-primary', 'is-link', 'is-info', 'is-warning']
这个过程非常便捷且立即就能获取所有的标签。
此外,在原有设置的基础上我们还新增了一个style属性,并非为了配合前端显示不同颜色。
实现标签详情视图
@bp.route('/tags/<int:tag_id>')
def tags(tag_id):
# 标签页
tag = Tag.query.get(tag_id)
return render_template('tags.html', post_list=tag.post, tag=tag)
创建标签页模板,在app/blog/templates/中创建tags.html,代码如下:
{% extends 'cate_list.html' %}
{% block title %}{{ tag }} {% endblock title %}
{% block hero %}{% endblock hero %}
{% 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">{{ tag }}</a></li>
</ul>
</nav>
{% endblock breadcrumb %}
{% block pagination %}
{% endblock pagination %}
模板中新增侧边栏模块
在app/blog/templates/cate_list.html中预留右侧块的位置并插入以下代码:
<div class="box is-shadowless" style="border:solid 1px #eee ;">
<h1 class="is-size-6 icon-text">
<span class="icon"><i class="mdi mdi-calendar-month-outline"></i></span>
归档
</h1>
<div class=" dropdown-divider"></div>
<ul>
{% for date in dates %}
<li class="pl-2"><a href="{{ url_for('blog.archive', date=date) }}">{{ date }}</a></li>
<div class="dropdown-divider"></div>
{% endfor %}
</ul>
</div>
<div class="box is-shadowless" style="border:solid 1px #eee ;">
<h1 class="is-size-6 icon-text">
<span class="icon"><i class="mdi mdi-tag-multiple-outline"></i></span>
标签
</h1>
<div class=" dropdown-divider"></div>
{% for tag in tags %}
<div class="tags">
<a class="tag {{ tag.style|random() }}" href="{{ url_for('blog.tags', tag_id=tag.id) }}">{{ tag.name }}</a>
</div>
{% endfor %}
</div>
至此,我们已经完成了侧边栏中的一套简单模块配置.在接下来的章节中,我们将开发并整合搜索功能及最新的内容推荐系统.
