我的个人博客从 Hexo 迁移到自建主机,主要是为了能自由的增减特性,和随时随地的更新博客(然而并没有)。所以考虑用 Python 的 Web 框架来写,由于我最开始是从 Flask 入门的,对它的源码也最了解,所以就选择了 Flask。总的来说,一个个人博客网站,主要包含以下几个功能:

  1. 文章的保存和展示
  2. 文章的分类和标签
  3. 文章的评论管理
  4. 对于动态博客来说,还有博客的后台部分

其中第 4 部分已经有单独的文章来介绍,使用的是前后端分离的方式访问 API。而第 3 部分我暂时打算用第三方的评论系统来管理(毕竟造个轮子也没有别人强大)。至于文章编写,我当然是选用 Markdown。

代码结构

使用 Flask 来写博客,首先要考虑的是项目结构——它不像 Django 一样,有固定的推荐结构,而是给了用户很大的自由空间来组织项目的代码,总的来说,有两大流派:

  1. 按业务划分,有点类似于 Django APP 的组织方式,我们会有 post, auth, user, comment 等部分。
  2. 按模块划分,分成操作数据库的 models 部分,渲染视图的 views 部分,处理模板的部分等等。

由于去掉了评论系统以后,博客的功能还是比较简单的,就是文章、分类、标签的管理,所以我使用了第二种组织方式,下面是我的代码结构:

flaskblog
├── __init__.py
├── admin.py
├── api             # API路由
├── app.py          # app对象
├── babel.cfg
├── cli.py          # app命令行
├── config.py       # 配置
├── md              # markdown解析器
├── models.py       # 数据库模型
├── templates       # HTML模板
├── templating.py   # 模板处理函数
├── translations    # 翻译文件
├── utils.py        # 通用函数
└── views.py        # 视图函数

Flask 扩展

用 Flask 来写 Web,最重要的是选用恰当合适的扩展。因为扩展质量良莠不齐,加上有些扩展很久不维护了,以往有很多其他文章中推荐的扩展,其实都不需要了(基于 Flask 1.0+版本),本着最小使用的原则,下面是我博客中用到的扩展:

  • Flask-Login 处理用户登录
  • 操作数据库的 ORM 和迁移必备组合 Flask-SQLAlchemy 和 Flask-Migrate
  • Flask-Whooshee 搜索索引
  • Flask-Moment 本地化时间(因为时间统一以 UTC 时间保存)
  • Flask-Assets 处理静态文件
  • Flask-Babel 国际化

由于后台部分是只有 API 的,而博客展示部分又没有表单,所以 Flask-WTF,Flask-Bootstrap 这些都不需要了,但 Flask-Login 还是要用来做后端用户态管理;Flask-Scripts 的功能已经内置到 Flask 中了,所以推荐大家都弃用掉这个扩展。Flask-Assets 主要用来 Minify CSS 和 JS 文件,它会自动在静态文件的 URL 中加上一个独特的后缀,这样不用更新静态文件后每次清除缓存。

Markdown 渲染

在 Python 的世界中已经有很多 Markdown 的解析器,但它们要么有时输出不符合预期(mistune),要么自己写起扩展功能来非常痛苦(python-markdown, python-markdown2),所以我一怒之下自己造了个轮子Marko,它默认符合 CommonMark 规范且自带 GFM 支持,还内置提供三个常用的扩展:脚注、目录生成、及中英文之间插入空格,欢迎大家提 PR 实现更多扩展。在博客项目中,我又利用 Marko 的扩展机制进行了进一步的定制:图片排版功能。使用方法是将多个图片放在一起(不换行),将渲染为多列图片。例:

![](//static.frostming.com/images/image1.jpg) ![](//static.frostming.com/images/image2.jpg)
![](//static.frostming.com/images/image3.jpg) ![](//static.frostming.com/images/image4.jpg)

渲染效果:

博客源码

更多实现细节可以参阅我已公开到 Github 上的源码