文章发布与 Markdown 支持:富文本编辑器与分页
📂 所属阶段:第四阶段 — 实战演练(道满博客)
🔗 相关章节:项目架构重构(Blueprints) · 数据库关系设计
前言:为什么选 Markdown + 轻量级渲染?
在开发技术博客(或者说“非完全可视化编辑的内容平台”)时,我们会面临几个常见的技术选型问题:
-
要不要用富文本编辑器(如 TinyMCE、Quill)?
这类编辑器对非技术用户友好,但生成的 HTML 冗余度高,很难保证前后端渲染的一致性; -
要不要完全自己写渲染?
没必要重复造轮子,开源的 Python-Markdown 已经覆盖了 99% 的常用需求; -
要不要加安全防护?
必须加! 用户提交的内容直接渲染是 XSS 攻击的重灾区。
综合来看,本文的方案是用户用纯 Markdown 提交内容 → 后端用 Python-Markdown 转成 HTML → 用 Bleach 库清理不安全标签 → 最后在模板里安全展示。
1. 快速搭建 Markdown 渲染环境
1.1 核心依赖安装
我们需要两个核心库:
markdown:负责把 Markdown 文本转换成 HTMLbleach:负责清理 XSS 相关的危险标签和属性
如果需要代码高亮的基础配色,可以顺便安装 pygments(扩展 codehilite 会用到):
1.2 封装安全的渲染工具函数
在 app/utils.py 里封装一个通用的 render_markdown 函数,这样全项目都可以复用,而且配置调整只需要改这一处:
Bleach 的清理规则最好和实际渲染需求匹配——只放行你明确需要的标签和属性,避免留下任何未预期的攻击面。
1.3 在文章详情页集成渲染
接下来在文章详情的路由和模板里调用这个函数:
1.3.1 路由修改
1.3.2 模板修改
注意要用 Jinja2 的 |safe 过滤器,否则渲染后的 HTML 会被转义成字符串显示:
2. 文章表单开发:支持分类、标签、状态切换
我们用 Flask-WTF 来实现表单,支持基本的验证、分类下拉、标签输入等功能:
提示:
coerce=int确保分类 ID 在服务端被正确转换为整数,避免类型不匹配。
3. 文章列表分页:提升浏览体验
当文章数量超过 10 篇时,一次性加载所有内容会很慢,而且体验不好,这时候分页就派上用场了。Flask-SQLAlchemy 自带了 paginate() 方法,非常方便。
3.1 路由实现分页查询
3.2 封装通用的分页宏
分页组件在很多页面都会用到(比如分类列表、标签列表),所以我们把它封装成 Jinja2 宏,放在 templates/macros/ 目录下:
3.3 在列表模板中引入宏
4. 文章标签处理:实现标签的增删改查关联
标签和文章是多对多的关系(一篇文章可以有多个标签,一个标签也可以对应多篇文章),我们在数据库设计阶段已经创建了中间表。现在需要封装一个函数,用来处理用户在表单中输入的标签字符串:
注意:这个函数需要在数据库事务内调用,或者配合
db.session.commit()使用,避免出现标签已添加但未保存的情况。
5. 小结
本文我们完成了以下核心功能:
- 安全的 Markdown 渲染:用
markdown库转换,用bleach库清理危险内容; - 完整的文章表单:支持标题、摘要、正文、分类、标签、发布状态;
- 通用的文章分页:用 Flask-SQLAlchemy 的
paginate()方法查询,用 Jinja2 宏封装分页组件; - 标签关联处理:封装函数解析标签字符串,实现多对多关系的增删改。
💡 安全提示回顾:永远不要对用户输入的任何内容(Markdown、HTML、纯文本的一部分)不做清理直接渲染!XSS 攻击的危害非常大,攻击者可以通过它窃取用户的 Cookie、发布虚假内容等。
🔗 扩展阅读

