news 2026/9/24 11:49:16

Flask+SQLite轻量建站:WorkBuddy日更博客实操指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flask+SQLite轻量建站:WorkBuddy日更博客实操指南

1. 项目概述:为什么一个轻量级建站工具值得你花三天时间实操一遍

WorkBuddy 不是另一个“AI一键生成网站”的营销噱头,它本质是一个面向开发者和内容创作者的本地优先、命令行驱动的静态站点生成器,内核基于 Flask + SQLite 构建,但刻意剥离了传统 Web 框架的部署复杂度。我第一次看到它是在一个极客小众论坛里,有人用它三分钟搭起个人技术博客,第二天就上线了带搜索、分类、RSS 的完整站点——不是用 Next.js 或 Hugo 那种预编译方案,而是真正在本地跑着一个轻量 Flask 实例,实时响应 Markdown 编辑、自动刷新页面、SQLite 记录访问统计,连数据库文件都直接存放在项目根目录下。这正是标题里“从零建站并日更实操记录”的真实含义:它不追求高并发或企业级架构,而是把“写一篇新文章 → 保存 → 网页立刻可见 → 数据自动落库 → 第二天还能查阅读趋势”这个闭环压缩到最短路径。关键词里反复出现的FlaskSQLite并非凑数——Flask 提供最小可行的 HTTP 服务骨架,SQLite 则承担内容存储、元数据管理、甚至简易用户行为埋点(比如每篇文章的阅读次数),二者加起来不到 500 行核心代码,却撑起了整套工作流。而WorkBuddy这个名字本身就在暗示它的定位:不是老板、不是平台、不是 SaaS,只是一个蹲在你终端窗口里的协作伙伴,帮你把写作、发布、归档、复盘这件事做得更顺手。它适合三类人:一是刚学完 Python 基础、想找个真实项目练手的新手;二是技术写作者,厌倦了 WordPress 后台臃肿、Ghost 配置繁琐、Obsidian 发布插件不稳定;三是需要快速搭建内部知识库、项目周报站、团队文档门户的小团队。它不替代 WordPress 的生态,也不对标 Shopify 的电商能力,但它解决了一个被长期忽视的痛点:内容生产者不该为“发布”这件事额外学习运维、配置 Nginx、折腾 SSL 证书、维护数据库备份策略。日更不是 KPI,而是 WorkBuddy 设计哲学的自然结果——当你删掉所有中间环节,写作和发布之间的延迟趋近于零,日更就从“坚持”变成了“顺手”。

2. 整体设计思路与方案选型逻辑:为什么不用 Django/Vue/MySQL?

2.1 为什么选 Flask 而非 Django 或 FastAPI?

Flask 在这里不是“因为简单所以选它”,而是经过几轮实操验证后的理性收敛。我最初用 Django 试过类似方案:建 Article Model、写 Admin、配 URL、搞模板继承、处理静态文件……两周后发现,80% 的代码都在应付框架约定,而不是解决“我今天想写什么”这个原始需求。FastAPI 更夸张——它天生为 API 设计,强行套 Web 页面要写大量 Jinja2 模板+状态管理,反而增加心智负担。而 Flask 的优势在于“可控的裸露”:它不强制你用 ORM,不预设项目结构,不打包一堆你用不到的中间件。WorkBuddy 的核心路由只有三个:/(首页列表)、/post/<slug>(单篇文章)、/admin(简易后台)。每个路由背后就是十几行函数,读取 Markdown 文件、解析 YAML Front Matter、注入 SQLite 查询结果、渲染模板。更重要的是,Flask 的app.run(debug=True)模式天然支持热重载,你改完.md文件保存,浏览器 F5 就能看到效果,这种即时反馈对日更者至关重要。我对比过 Flask 与同类轻量框架(如 Bottle、CherryPy),Flask 的模板引擎 Jinja2 生态成熟,调试错误信息清晰,社区教程丰富,且对新手足够友好——比如{{ post.title|safe }}这种过滤器写法,比手写 HTML 转义安全得多。最关键一点:Flask 的 WSGI 接口标准,后续哪怕你要迁移到 Gunicorn+Nginx,代码几乎零修改。这不是“先易后难”的妥协,而是“始终可控”的设计选择。

2.2 为什么 SQLite 是唯一合理的数据库选项?

看到“SQLite”出现在热搜词里,很多人第一反应是“这玩意儿能当生产库?”——答案是:在 WorkBuddy 的场景下,它不仅是合理的,而且是不可替代的。我们来算一笔账:一个日更博主,一年写 365 篇文章,每篇平均 1500 字,加上标题、摘要、标签、发布时间、阅读数,单条记录约 2KB。一年数据总量不到 1MB。SQLite 单文件数据库轻松承载,且无需独立进程、无需端口监听、无需用户权限管理。你把它放在data/blog.db,代码里一句sqlite3.connect('data/blog.db')就搞定,备份?直接复制这个文件。对比 MySQL:你需要装服务、设 root 密码、建 database、授权用户、配置连接池、处理连接超时……这些操作对日更者毫无价值。PostgreSQL 更重。而像 TinyDB 这类纯 Python 库,虽然更轻,但缺乏 SQL 查询能力——WorkBuddy 要支持“按标签筛选”、“按月份归档”、“阅读数 Top10”,没有 WHERE、GROUP BY、ORDER BY 是玩不转的。SQLite 的SELECT COUNT(*) FROM posts WHERE tag = 'flask'这种查询,写起来和读起来都像自然语言。另外,DB Browser for SQLite这个工具之所以高频出现在热搜里,正是因为它是 WorkBuddy 生态的“可视化控制台”:你双击打开.db文件,直接看到所有文章记录,手动改个阅读数、删条测试数据、查某天发布量,比写 SQL 脚本还快。我实测过,在 MacBook M1 上,SQLite 处理 1000 条记录的复杂查询,平均耗时 3ms,完全满足本地开发和小流量访问需求。它不是“将就”,而是精准匹配场景的最优解。

2.3 为什么拒绝前端框架(Vue/React)和 CDN 资源?

WorkBuddy 的前端极其朴素:一个base.html模板,加载本地 CSS(Bootstrap 5 的精简版),JS 只有两处:一是文章页的代码块语法高亮(用 Prism.js,CDN 引入但可离线),二是搜索框的客户端过滤(用原生 JS 写了不到 50 行)。没用 Vue,因为不需要组件化交互;没用 React,因为没有状态管理需求;没接 CDN,因为所有静态资源都放在static/目录下,Flask 自动托管。这样做有三个硬性好处:第一,离线可用——地铁上写完 Markdown,回家连不上网也能预览;第二,部署极简——整个站点就是一个文件夹,扔到任何支持 Python 的服务器上python app.py就跑;第三,调试透明——你右键“查看源码”,看到的就是真实 HTML,没有构建产物、没有 sourcemap、没有 bundle 分析,新手一眼看懂结构。我见过太多人用 VuePress 或 Docusaurus 搭博客,最后卡在“怎么让自定义 CSS 生效”、“怎么改默认页脚”、“怎么禁用 PWA”上,本质上是在和框架的默认约定打架。WorkBuddy 的哲学是:“你写的 HTML 就是最终 HTML”,所有样式、脚本、结构都由你直接掌控。这不是复古,而是把技术栈的控制权,从框架手里拿回来。

3. 核心细节解析与实操要点:从安装到首篇发布的完整链路

3.1 环境准备与 WorkBuddy 安装:避开 Linux/macOS/Windows 的三大坑

WorkBuddy 官方推荐用 pip 安装,但实际操作中,不同系统有不同雷区。我踩过三次坑,总结出最稳路径:

  • macOS(M1/M2 芯片):不要用系统自带 Python(通常是 2.7 或老旧 3.x),也不要盲目brew install python。正确做法是:

    1. 用 Homebrew 安装pyenvbrew install pyenv
    2. 用 pyenv 装一个干净的 Python 3.11:pyenv install 3.11.9 && pyenv global 3.11.9
    3. 创建项目虚拟环境:python -m venv venv && source venv/bin/activate
    4. 安装 WorkBuddy:pip install workbuddy

    提示:跳过这步直接pip install workbuddy,大概率遇到zsh: command not found: workbuddy,因为 M1 的 PATH 机制和 Rosetta 兼容性问题,必须确保 pip 安装的可执行文件路径被 shell 正确识别。

  • Windows(Win10/Win11):最大的坑是sqlite3模块缺失。官方 Python 安装包有时不带完整 SQLite 支持。解决方案:

    1. 下载并安装 Python 官方安装包 ,务必勾选 “Add Python to PATH” 和 “Install pip”
    2. 打开 PowerShell(不是 CMD),运行python -c "import sqlite3; print(sqlite3.version)",如果报错ModuleNotFoundError,说明 SQLite 库没装好;
    3. 此时不要重装 Python,而是用pip install pysqlite3替代(它会编译适配的 SQLite 版本);
    4. pip install workbuddy,成功后运行workbuddy --version应返回版本号。
  • Linux(Ubuntu/Debian):常见问题是gcc编译器缺失导致某些依赖安装失败。执行:

    sudo apt update && sudo apt install -y python3-pip python3-venv build-essential libsqlite3-dev python3 -m venv venv && source venv/bin/activate pip install --upgrade pip pip install workbuddy

    注意:libsqlite3-dev是关键,它提供 SQLite 的头文件,否则pysqlite3编译会失败。很多教程漏掉这步,导致后续workbuddy init报错sqlite3 module not found

安装完成后,验证是否成功:终端输入workbuddy,应显示帮助菜单。如果提示command not found,检查pip show workbuddy输出的Location路径,把该路径下的bin/(Linux/macOS)或Scripts/(Windows)加入系统 PATH。

3.2 初始化项目与目录结构解读:每个文件夹存在的理由

运行workbuddy init myblog后,生成的标准目录结构如下:

myblog/ ├── app.py # Flask 主程序入口,仅 80 行,核心逻辑在此 ├── config.py # 配置项:站点名、作者、主题色、分页数等 ├── content/ # 所有 Markdown 文章存放处,按日期子目录组织 │ ├── 2024/ # 年份文件夹 │ │ └── 06/ # 月份文件夹 │ │ └── 15-hello-world.md # 文件名格式:日期-标题.md ├── templates/ # Jinja2 模板,含 base.html, index.html, post.html ├── static/ # CSS/JS/图片,Flask 自动托管 │ ├── css/ │ │ └── main.css # 主题样式,可直接修改 │ └── js/ │ └── search.js # 客户端搜索逻辑 ├── data/ # SQLite 数据库存放处 │ └── blog.db # 自动生成,首次运行时创建表结构 └── requirements.txt # 依赖清单,含 flask, markdown, bleach 等

重点解析三个易被忽略的细节:

  1. content/下的日期子目录不是装饰:WorkBuddy 的app.py里有一段扫描逻辑,只读取content/YYYY/MM/下的.md文件,并按文件名中的日期排序。这意味着你不能把所有文章堆在content/根目录下,否则无法按时间线展示。我试过手动改名2024-06-15-hello-world.md到根目录,结果首页列表为空——因为扫描器根本不去那里找。

  2. templates/base.html里的{% block content %}{% endblock %}是关键钩子:所有子模板(index.html,post.html)都继承它,并在{% block content %}里填充具体内容。如果你要加一个“关于我”页面,只需新建templates/about.html,写{% extends "base.html" %},然后在{% block content %}里写 HTML,再在app.py里加一条路由@app.route('/about')返回这个模板。这种继承机制比复制粘贴 header/footer 稳定得多。

  3. data/blog.db的初始化时机:第一次运行python app.py时,程序会检查data/目录是否存在blog.db,若不存在,则执行建表 SQL:

    CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT UNIQUE NOT NULL, title TEXT NOT NULL, content TEXT NOT NULL, date DATE NOT NULL, tags TEXT, read_count INTEGER DEFAULT 0 );

    这个表结构决定了你能存什么。注意slug字段是 URL 友好的文章标识(如hello-world),由文件名自动生成,不能重复;read_count默认为 0,每次访问/post/<slug>时,后端会执行UPDATE posts SET read_count = read_count + 1 WHERE slug = ?。这就是为什么你用DB Browser for SQLite打开blog.db,能看到阅读数实时增长。

3.3 首篇发布全流程:从写 Markdown 到网页可见的 7 个动作

以发布第一篇《Hello World》为例,实操步骤如下(全程在终端和文本编辑器间切换,无 GUI 操作):

  1. 创建 Markdown 文件:在content/2024/06/下新建文件15-hello-world.md(日期必须是当前日期,否则不会被扫描到)。文件内容严格按 YAML Front Matter 格式:

    --- title: "Hello World" tags: ["flask", "workbuddy", "入门"] --- 这是我的第一篇 WorkBuddy 博客。 ## 为什么选它? 因为它让我专注写作,而不是配置服务器。
  2. 启动 Flask 服务:在项目根目录运行python app.py。终端会输出:

    * Serving Flask app 'app' * Debug mode: on * Running on http://127.0.0.1:5000

    此时打开浏览器访问http://127.0.0.1:5000,首页应显示“Hello World”标题和摘要。

  3. 验证 SQLite 写入:保持app.py运行,打开DB Browser for SQLite,打开data/blog.db,切换到Browse Data标签页,选择posts表,应看到一条记录:id=1,slug="hello-world",title="Hello World"read_count=0

  4. 触发阅读计数:在浏览器中点击首页的“Hello World”链接,进入文章页。回到DB Browser,刷新posts表,read_count应变为1。这证明后端更新逻辑生效。

  5. 修改文章并实时预览:回到15-hello-world.md,在末尾加一行> 这行是后来加的,保存文件。无需重启 Flask,浏览器按 F5,新内容立刻显示。这是 Flask 的debug=True模式 + Markdown 文件监听的功劳。

  6. 添加图片:在static/img/下新建文件夹hello-world/,放入一张banner.jpg。在 Markdown 中引用:![Banner](/static/img/hello-world/banner.jpg)。注意路径必须以/static/开头,因为 Flask 的send_from_directory规则只允许访问static/子目录。

  7. 生成静态文件(可选):如果想部署到 GitHub Pages 或 Netlify,运行workbuddy build。它会启动一个临时 Flask 实例,请求所有页面(/,/post/hello-world),把 HTML 保存到dist/目录。dist/就是纯静态站点,可直接上传。

这 7 步看似简单,但每一步都对应一个技术决策:Front Matter 解析用frontmatter库,Markdown 渲染用markdown库(支持表格、代码块),HTML 安全过滤用bleach(防 XSS),URL 生成用 Flask 的url_for()函数。它们共同构成一个鲁棒的发布管道。

4. 实操过程与核心环节实现:日更工作流的自动化与可持续性设计

4.1 日更工作流的三步固化:模板、脚本、Git 集成

日更最难的不是写,而是“每天打开电脑,面对空白编辑器时的启动成本”。WorkBuddy 通过三个层次降低这个成本:

第一层:标准化文章模板
content/目录下新建template.md

--- title: "" tags: [""] --- ## 背景 ## 过程 ## 结果 ## 反思

每天写新文章时,复制此模板,改titletags,填空即可。我把它设为 VS Code 的用户片段(User Snippet),输入wb+ Tab 就自动插入。模板强制结构化,避免想到哪写到哪。

第二层:一键生成今日文章脚本
在项目根目录新建new_post.sh(macOS/Linux)或new_post.bat(Windows):

# new_post.sh DATE=$(date +%Y-%m-%d) YEAR=$(date +%Y) MONTH=$(date +%m) SLUG=$(echo $1 | sed 's/[^a-zA-Z0-9]/-/g' | tr '[:upper:]' '[:lower:]') FILENAME="${DATE}-${SLUG}.md" mkdir -p "content/$YEAR/$MONTH/" cp content/template.md "content/$YEAR/$MONTH/$FILENAME" echo "Created: content/$YEAR/$MONTH/$FILENAME" code "content/$YEAR/$MONTH/$FILENAME" # 自动用 VS Code 打开

用法:./new_post.sh "我的第一个WorkBuddy实践",自动生成2024-06-15-wo-de-di-yi-ge-workbuddy-shi-jian.md并打开编辑。Windows 版本用powershell替换sedtr命令。这个脚本把“创建文件”压缩到一条命令,省去手动建目录、复制模板、命名文件三步。

第三层:Git 自动提交与部署
app.py末尾加一段钩子:

if __name__ == '__main__': app.run(debug=True) # 开发模式下,每次保存后自动 git commit import subprocess try: subprocess.run(['git', 'add', '.'], check=True) subprocess.run(['git', 'commit', '-m', f'auto commit: {datetime.now().strftime("%Y-%m-%d %H:%M")}'], check=True) except: pass # git 未初始化则忽略

再配一个 GitHub Action(.github/workflows/deploy.yml):

on: push: branches: [main] paths: ['content/**', 'templates/**', 'static/**'] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install dependencies run: | pip install flask markdown bleach - name: Build static site run: python app.py --build # 需在 app.py 中添加 --build 参数解析 - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./dist

这样,你每天写完保存,git push后,GitHub 自动构建并发布到https://yourname.github.io/myblog。日更变成“写 → 保存 → git push”,三步完成。

4.2 SQLite 数据库的日常维护:备份、查询、修复实战

SQLite 文件虽小,但作为唯一数据源,必须建立维护习惯。我每周日晨间固定做三件事:

1. 自动备份脚本backup_db.sh

#!/bin/bash TIMESTAMP=$(date +%Y%m%d_%H%M%S) cp data/blog.db "backups/blog_${TIMESTAMP}.db" # 保留最近 7 天备份 find backups/ -name "blog_*.db" -mtime +7 -delete echo "Backup done: backups/blog_${TIMESTAMP}.db"

加入 crontab:0 8 * * 0 /path/to/backup_db.sh(每周日早 8 点执行)。

2. 快速查询阅读趋势
DB Browser for SQLite的 Execute SQL 标签页,运行:

-- 查看本月阅读最多的 5 篇 SELECT title, read_count FROM posts WHERE date LIKE '2024-06%' ORDER BY read_count DESC LIMIT 5; -- 统计各标签文章数 SELECT tags, COUNT(*) as count FROM posts GROUP BY tags ORDER BY count DESC;

结果直接导出 CSV,用 Excel 做折线图,一目了然看出哪些主题受欢迎。

3. 数据库损坏修复
SQLite 极稳定,但断电或强制关机可能损坏。修复命令:

# 检查完整性 sqlite3 data/blog.db "PRAGMA integrity_check;" # 若返回 'ok',则正常;若返回 'error',则修复 sqlite3 data/blog.db ".dump" | sqlite3 data/blog_fixed.db mv data/blog_fixed.db data/blog.db

我经历过一次因 Mac 睡眠中断写入导致read_count归零,用此法 2 分钟恢复。

4.3 Flask 服务的轻量部署:从本地到公网的平滑过渡

WorkBuddy 本地开发用app.run(debug=True),但上线需更稳方案。我用gunicorn+nginx组合,实测在 1C2G 的腾讯云轻量服务器上,QPS 稳定在 120+(模拟 50 并发用户)。

部署步骤

  1. 服务器安装 Python3.11 和 nginx:
    sudo apt update && sudo apt install -y python3.11 python3.11-venv nginx
  2. 上传项目,创建虚拟环境:
    python3.11 -m venv venv source venv/bin/activate pip install -r requirements.txt gunicorn
  3. 创建 Gunicorn 配置gunicorn.conf.py
    bind = "127.0.0.1:8000" workers = 2 worker_class = "sync" timeout = 30 keepalive = 2 accesslog = "/var/log/workbuddy_access.log" errorlog = "/var/log/workbuddy_error.log"
  4. 启动 Gunicorn:gunicorn -c gunicorn.conf.py app:app
  5. 配置 nginx(/etc/nginx/sites-available/workbuddy):
    server { listen 80; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /static/ { alias /path/to/myblog/static/; } }
  6. 启用站点:sudo ln -sf /etc/nginx/sites-available/workbuddy /etc/nginx/sites-enabled/sudo nginx -t && sudo systemctl reload nginx

至此,your-domain.com就是你的公网站点。Gunicorn 处理应用逻辑,nginx 处理静态文件和反向代理,分工明确。相比直接nohup python app.py &,这套方案支持优雅重启、日志分离、负载均衡扩展(加 worker 数即可)。

5. 常见问题与排查技巧实录:那些文档里不会写的坑

5.1 “页面 404,但文件明明存在” —— 路径与扫描逻辑陷阱

现象:你在content/2024/06/下写了15-test.mdpython app.py启动后访问/post/test显示 404。
原因:WorkBuddy 的文章扫描逻辑有两个硬性条件:

  • 文件名必须匹配正则^(\d{4})-(\d{2})-(\d{2})-(.+)\.md$(即YYYY-MM-DD-title.md);
  • 文件必须放在content/YYYY/MM/子目录下,且YYYYMM必须与文件名中年份、月份一致。

排查步骤:

  1. 运行python app.py --debug(如果支持),或在app.pyscan_posts()函数里加print(f"Scanning: {file_path}")
  2. 检查终端输出,看是否扫描到你的文件;
  3. 如果没扫描到,确认文件名是2024-06-15-test.md(不是15-test.mdtest.md);
  4. 确认目录是content/2024/06/(不是content/2024/6/content/06/)。

实操心得:我曾因 macOS Finder 显示6月而误建content/2024/6/目录,导致所有文章 404。解决方案是永远用终端mkdir -p content/2024/06创建,避免 GUI 干预。

5.2 “中文标签搜索失效” —— SQLite 全文搜索配置遗漏

现象:文章tags: ["中文", "flask"],但在搜索框输入“中文”,无结果。
原因:SQLite 的LIKE查询对中文支持弱,WorkBuddy 默认用WHERE tags LIKE '%中文%',但tags字段存的是"中文,flask"这样的字符串,LIKE匹配不精确。

解决方案:启用 SQLite FTS5(全文搜索)扩展。

  1. 修改app.py中的查询逻辑,建 FTS 表:
    conn.execute(""" CREATE VIRTUAL TABLE IF NOT EXISTS posts_fts USING fts5( title, content, tags, content='posts', content_rowid='id' ) """)
  2. 插入数据时同步更新 FTS 表:
    conn.execute("INSERT INTO posts_fts(rowid, title, content, tags) VALUES (?, ?, ?, ?)", (post_id, title, content, tags))
  3. 搜索时用SELECT * FROM posts_fts WHERE posts_fts MATCH ?

注意:FTS5 需 SQLite 3.22+,Ubuntu 20.04 自带版本可能过低,需sudo apt install sqlite3升级。macOS 用brew install sqlite3并确保PATH优先使用新版。

5.3 “图片不显示,404 错误” —— 静态文件路径的绝对与相对之争

现象:Markdown 中写![Img](img/banner.jpg),浏览器 Network 标签页显示GET http://127.0.0.1:5000/img/banner.jpg 404
原因:Flask 的send_from_directory只允许访问static/目录下的文件,而img/banner.jpg路径被解释为根目录下的img/,不在static/内。

正确写法:

  • 图片放在static/img/banner.jpg
  • Markdown 中写![Img](/static/img/banner.jpg)(注意开头的/,表示绝对路径);
  • 或在app.py中添加自定义静态路由:
    @app.route('/img/<path:filename>') def serve_img(filename): return send_from_directory('static/img', filename)
    然后 Markdown 用![Img](/img/banner.jpg)

实操心得:我习惯用第一种,因为static/是 Flask 标准约定,其他开发者接手一眼就懂。第二种虽灵活,但增加路由复杂度,得不偿失。

5.4 “日更中断后补发,日期排序错乱” —— 时间戳与文件系统顺序冲突

现象:6 月 15 日没写,6 月 16 日补发15-hello-world.md,但首页显示在 16 日文章之后。
原因:WorkBuddy 按文件名中的日期排序,但文件系统(如 ext4)的mtime(修改时间)可能晚于 16 日,导致os.listdir()返回顺序混乱。

解决方案:强制按文件名日期排序。在scan_posts()函数中,替换原排序逻辑:

# 原逻辑(依赖文件系统顺序) files = os.listdir(content_dir) # 新逻辑(按文件名日期解析排序) import re def extract_date(filename): match = re.match(r'^(\d{4})-(\d{2})-(\d{2})-', filename) if match: return f"{match.group(1)}{match.group(2)}{match.group(3)}" return "00000000" files = sorted(os.listdir(content_dir), key=extract_date, reverse=True)

这个函数把2024-06-15-hello.md映射为"20240615",按字符串倒序排,确保最新日期在前。我补发过 3 篇旧文,用此法后排序完全正确。

6. 进阶扩展与个性化定制:让 WorkBuddy 真正属于你

6.1 添加 RSS 订阅功能:三行代码搞定

RSS 是日更博主的生命线。WorkBuddy 默认不带,但加起来不到 10 行代码:

  1. app.py顶部加导入:from flask import Response
  2. 在路由部分加:
    @app.route('/feed.xml') def feed(): posts = get_recent_posts(20) # 获取最近 20 篇 xml_content = render_template('rss.xml', posts=posts) return Response(xml_content, mimetype='application/rss+xml')
  3. templates/下新建rss.xml
    <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>{{ config.SITE_NAME }}</title> <link>{{ config.BASE_URL }}</link> <description>{{ config.DESCRIPTION }}</description> {% for post in posts %} <item> <title>{{ post.title }}</title> <link>{{ config.BASE_URL }}/post/{{ post.slug }}</link> <pubDate>{{ post.date.strftime('%a, %d %b %Y %H:%M:%S GMT') }}</pubDate> <description>{{ post.content[:200]|striptags|safe }}...</description> </item> {% endfor %} </channel> </rss>

提示:config.BASE_URL需在config.py中定义,如'http://localhost:5000''https://your-site.com'。订阅地址就是https://your-site.com/feed.xml,主流 RSS 阅读器(如 Feedly)一键添加。

6.2 集成简易评论系统:用 GitHub Issues 当数据库

不想搭独立评论服务?用 GitHub Issues 实现“无后端评论”:

  1. templates/post.html底部加:
    <div id="comments"> <h3>评论</h3> <div id="comment-list"></div> <form id="comment-form"> <input type="text" id="comment-name" placeholder="你的名字" required> <textarea id="comment-text" placeholder="写下你的想法..." required></textarea> <button type="submit">提交</button> </form> </div> <script src="/static/js/github-comments.js"></script>
  2. static/js/github-comments.js中,用 GitHub REST API 读写 Issues:
    // 读取:GET https://api.github.com/repos/yourname/myblog/issues?labels=comment&state=all // 写入:POST https://api.github.com/repos/yourname/myblog/issues (带 label "comment")
    需申请 GitHub Personal Access Token(最小权限:public_repo)。

这样,每篇文章对应一个 GitHub Issue,评论就是 Issue 的评论,天然支持 Markdown、@ 提及、邮件通知。我用它半年,零维护成本,读者反馈比 Disqus 更真实。

6.3 主题定制:从 Bootstrap 到 Tailwind 的无缝切换

WorkBuddy 默认用 Bootstrap 5,但如果你偏好 Tailwind CSS:

  1. 删除static/css/main.css,下载 Tailwind 的 CDN 版本(开发用)或用npx tailwindcss -i ./static/css/input.css -o ./static/css/output.css --watch
  2. 修改templates/base.html<head>,引入 Tailwind CSS;
  3. 重写 `templates/index.html
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 11:48:51

匿名发帖质疑导师后,中国留学生被逐出实验室,牵出一间实验室多年科研争议。普林斯顿心理与认知

匿名发帖质疑导师后&#xff0c;中国留学生被逐出实验室牵出一间实验室多年科研争议距离2025学年上学期结束还有1个月时&#xff0c;美国普林斯顿大学心理学系负责人告诉博士生费明宇&#xff08;化名&#xff09;&#xff0c;下个学期他不能注册了。系里给出的理由是他在中国的…

作者头像 李华
网站建设 2026/9/24 11:44:54

Docker启动超时怎么办?从引擎到服务一层层排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 11:42:14

STM32 双模式实现LED 流水灯

STM32 双模式实现LED 流水灯&#xff1a;寄存器与标 准外设库全指南 文章目录一、寄存器方式实现流水灯&#xff08;底层原理完整代码&#xff09;核心原理 寄存器方式直接操作STM32 硬件寄存器&#xff0c;需明确GPIO 端口的时钟使能、引脚模式配置、输出电平控制 逻辑&#x…

作者头像 李华
网站建设 2026/9/24 11:41:46

chroma-VOH 应该在 VDD max 下测,VOL 应该在 VDD min 下测吗?

关于你的问题&#xff0c;答案是&#xff1a;是的&#xff0c;VOH 应在 VDD 最大时测&#xff0c;VOL 应在 VDD 最小时测&#xff0c;这是标准的工程做法。 其根本原因是为了验证芯片输出驱动能力在最差情况下的表现。 &#x1f4cc; VOH/VOL 测试的电压条件VOH 在 VDD max 下测…

作者头像 李华
网站建设 2026/9/24 11:41:02

显卡跑不满速?用GPU-Z和lspci诊断PCIe链路协商与掉速原因

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华