1. 为什么我选择 WorkBuddy + Flask + SQLite 这套组合
1.1 从“想做个站”到“真的跑起来”之间差了什么
很多人第一次冒出“自己建个站”的念头,往往是因为看到了某个很酷的页面,或者手里有一批想展示的数据。但真动手的时候,问题就来了:域名怎么弄、服务器买哪家、环境怎么配、数据库怎么连、前端后端怎么对接……每一步都能卡住人。我见过太多人卡在“环境配置”这一步就放弃了,甚至连 Python 都没装明白。
WorkBuddy 这个工具吸引我的地方,是它把“建站”这件事从“搭环境、写配置、调依赖”的泥潭里拽了出来。它更像是一个工作台,你告诉它你要做什么,它帮你把项目骨架、依赖关系、甚至部分业务逻辑都理清楚。但工具再好,底层的东西你得懂——不然出了问题你连从哪查都不知道。所以我选的是 WorkBuddy 做效率工具,Flask 做 Web 框架,SQLite 做数据存储。这套组合的好处是:轻、快、可控。Flask 本身足够简单,一个文件就能跑起来一个 Web 服务;SQLite 不需要单独装数据库服务,一个文件就是整个库;WorkBuddy 则帮你把重复性的代码生成和项目管理工作接过去。
这套方案适合谁?适合有一点 Python 基础、想快速验证一个想法、不想在运维上花太多时间的人。如果你连 Python 都没装过,也没关系,后面我会把安装和配置的每一步都拆开讲。但如果你期望的是“一键生成一个淘宝”,那这套方案不适合你——它更适合做中小型的信息展示、数据管理、内部工具类的站点。
1.2 为什么不是 WordPress 或 Shopify
这里得说清楚一个选型逻辑。WordPress 和 Shopify 都是非常成熟的建站方案,但它们的定位和 Flask 自建站完全不同。WordPress 本质上是“内容管理系统”,你装好之后得到的是一个已经成型的博客/企业站框架,你要做的是“往里填内容”和“装插件”。Shopify 更垂直,它是电商 SaaS,你租的是它的服务,数据在它那里,你按月付费。
而 Flask + SQLite 自建站,你得到的是一个“空白的画布”。你要自己定义数据表、自己写路由、自己设计页面。听起来更麻烦,但换来的是完全的控制权和零平台依赖。你的数据在你自己的机器上,你的代码你想怎么改就怎么改,不需要看任何平台的脸色。对于“日更”这种需要频繁调整内容结构和展示逻辑的场景,自建站的灵活性优势非常明显。
WorkBuddy 在这中间扮演的角色,是帮你把“画布”准备好,把画笔和颜料摆好,甚至帮你画好草稿线。但最终画成什么样,还是你说了算。
1.3 日更场景对技术栈的特殊要求
“日更”这个词听起来简单,但对技术栈的要求其实不低。每天都要更新内容,意味着你的发布流程必须足够短——如果每次更新都要折腾半小时环境,那肯定坚持不下去。所以技术栈必须满足几个条件:启动快、改起来快、数据写入快、不容易崩。
Flask 的轻量特性在这里很关键。一个典型的 Flask 应用启动只需要几百毫秒,你改完代码保存,服务自动重载,刷新页面就能看到效果。SQLite 的写入速度对于日更级别的数据量来说绰绰有余,单条插入通常在毫秒级。WorkBuddy 则可以在你每次新增内容类型时,快速生成对应的模型、路由和模板骨架,省去大量重复劳动。
我实测下来,从打开电脑到发布一篇新内容,整个流程可以压缩到 3 分钟以内。这个效率是支撑“日更”这个习惯的技术基础。
2. 环境搭建:从零到跑通第一个页面
2.1 Python 安装与虚拟环境配置
不管你用 Windows、macOS 还是 Linux,第一步都是把 Python 装好。我建议直接去 Python 官网下载 3.10 或以上的版本,安装时务必勾选“Add Python to PATH”——这个选项在 Windows 上尤其重要,不勾的话后面命令行里敲python会提示找不到命令。
装完之后验证一下:
python --version如果显示的是 3.10 以上的版本号,就说明装好了。接下来是虚拟环境。虚拟环境的作用是把你这个项目的依赖和系统里其他 Python 包隔离开,避免版本冲突。操作很简单:
python -m venv venv这会在当前目录下创建一个叫venv的文件夹。然后激活它:
- Windows:
venv\Scripts\activate - macOS/Linux:
source venv/bin/activate
激活之后,命令行前面会出现(venv)的标识。以后每次开发前都要先激活虚拟环境,这是一个必须养成的习惯。
注意:虚拟环境文件夹不要提交到代码仓库,也不要手动去改里面的文件。它就是一个隔离层,坏了就删掉重建。
2.2 Flask 与 SQLite 的依赖安装
虚拟环境激活后,安装 Flask:
pip install flaskSQLite 不需要单独安装,Python 标准库自带sqlite3模块。但如果你想要一个图形化的工具来查看和编辑数据库文件,我强烈推荐DB Browser for SQLite。这个工具可以让你像用 Excel 一样查看表结构、浏览数据、执行 SQL 语句,对于调试和日常维护非常方便。
如果你还想用 ORM(对象关系映射)来操作数据库,可以装 Flask-SQLAlchemy:
pip install flask-sqlalchemyORM 的好处是你不用手写 SQL,用 Python 类的方式就能定义表和查询。但代价是多了一层抽象,出问题的时候排查起来会稍微麻烦一点。我的建议是:初期用原生 SQL 先把逻辑跑通,等业务复杂了再考虑上 ORM。
2.3 WorkBuddy 的安装与初始化项目
WorkBuddy 的安装方式取决于你用的版本。国际版和国内版的安装流程略有差异,但核心逻辑是一样的:下载安装包、运行安装程序、登录账号、创建项目。安装完成后,你可以在 WorkBuddy 里新建一个项目,选择 Flask 作为项目类型,它会自动生成一个标准的 Flask 项目结构:
myproject/ ├── app.py ├── templates/ ├── static/ ├── requirements.txt └── instance/这个结构里,app.py是主入口,templates放 HTML 模板,static放 CSS/JS/图片,instance通常用来放数据库文件。WorkBuddy 还会帮你生成一个基础的requirements.txt,里面列出了项目依赖。
提示:WorkBuddy 生成的项目结构是一个起点,不是终点。你可以根据自己的需要调整目录,比如把路由拆成多个文件、把模型单独放一个目录。但初期建议先保持简单,一个
app.py能跑通所有功能就够了。
2.4 跑通第一个 Hello World 页面
在app.py里写一个最简单的路由:
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return 'Hello, WorkBuddy!' if __name__ == '__main__': app.run(debug=True)然后在命令行里运行:
python app.py你会看到类似这样的输出:
* Running on http://127.0.0.1:5000打开浏览器访问这个地址,如果看到 “Hello, WorkBuddy!”,说明环境已经跑通了。这一步看起来简单,但它是后面所有功能的基础。如果这一步卡住了,后面的都不用谈。
3. 数据库设计:用 SQLite 存什么、怎么存
3.1 日更内容的数据表结构设计
日更站点的核心数据就是“内容”。一条内容通常包含这些字段:标题、正文、发布时间、更新时间、标签、状态(草稿/已发布)。用 SQLite 建表的话,SQL 语句大概长这样:
CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT NOT NULL, tags TEXT DEFAULT '', status TEXT DEFAULT 'draft', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );这里有几个设计决策值得说明。id用INTEGER PRIMARY KEY AUTOINCREMENT是 SQLite 的标准自增主键写法。status字段用文本来存状态而不是用数字,是为了可读性——你直接看数据库就能明白这条是草稿还是已发布。created_at和updated_at用TIMESTAMP类型并设置默认值,这样插入数据时不需要手动传时间。
如果你还要存标签的关联关系,可以再加一张标签表和一张关联表。但初期建议先用逗号分隔的文本存标签,简单直接,查询的时候用LIKE就能模糊匹配。等标签数量多了再考虑拆表。
3.2 用 DB Browser 管理数据库文件
DB Browser for SQLite 的使用非常直观。打开软件后,点击“打开数据库”,选择你的.db文件,就能看到所有的表。你可以直接在界面上执行 SQL、浏览数据、导出 CSV。对于日更场景,我经常用它来快速检查某条内容是否写入成功,或者手动修正一些数据。
有一个细节要注意:Flask 应用运行的时候,数据库文件是被占用的。如果你在 DB Browser 里修改了数据,Flask 那边不一定能立刻看到变化,因为 SQLite 有缓存机制。反过来,如果 Flask 正在写入,DB Browser 可能会提示数据库被锁定。所以建议在修改数据库之前,先把 Flask 服务停掉。
3.3 数据库文件的存放位置与备份策略
SQLite 数据库就是一个文件,所以备份极其简单——复制文件就行。但要注意存放位置。我习惯把它放在项目的instance目录下,然后在app.py里用绝对路径来引用:
import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) DB_PATH = os.path.join(BASE_DIR, 'instance', 'site.db')这样不管你在哪个目录下运行python app.py,数据库路径都是正确的。备份的话,我设置了一个简单的定时任务,每天凌晨把.db文件复制到一个带日期的备份目录里。对于日更站点,这个操作能救命——万一哪天误删了数据,至少还有昨天的备份。
注意:SQLite 不支持多进程同时写入。如果你的 Flask 应用用了多进程模式(比如 gunicorn 的多个 worker),写入操作可能会冲突。对于日更这种低并发场景,用单进程就够了。
4. 核心功能实现:从发布到展示的完整链路
4.1 发布页面的表单设计与后端接收
发布页面就是一个 HTML 表单,包含标题输入框、正文文本域、标签输入框和提交按钮。用 Flask 的render_template渲染模板,用request.form接收数据。关键代码如下:
from flask import Flask, render_template, request, redirect, url_for import sqlite3 @app.route('/publish', methods=['GET', 'POST']) def publish(): if request.method == 'POST': title = request.form['title'] content = request.form['content'] tags = request.form.get('tags', '') conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute( 'INSERT INTO posts (title, content, tags, status) VALUES (?, ?, ?, ?)', (title, content, tags, 'published') ) conn.commit() conn.close() return redirect(url_for('index')) return render_template('publish.html')这里用?占位符来传参数,而不是直接拼接字符串,是为了防止 SQL 注入。这是一个必须遵守的安全习惯,不管你的站点是不是只有自己用。
4.2 首页列表与详情页的路由拆分
首页展示所有已发布内容的列表,按时间倒序排列。详情页根据id展示单条内容。路由设计如下:
@app.route('/') def index(): conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute("SELECT id, title, tags, created_at FROM posts WHERE status='published' ORDER BY created_at DESC") posts = cursor.fetchall() conn.close() return render_template('index.html', posts=posts) @app.route('/post/<int:post_id>') def detail(post_id): conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() cursor.execute("SELECT * FROM posts WHERE id=?", (post_id,)) post = cursor.fetchone() conn.close() return render_template('detail.html', post=post)列表页只查需要的字段,不要SELECT *,这样可以减少数据传输量。详情页才查全部字段。这是一个小优化,但在数据量大了之后效果明显。
4.3 用 WorkBuddy 生成模板骨架并微调
WorkBuddy 可以根据你的数据表结构自动生成对应的 HTML 模板骨架。比如你告诉它“我有一个 posts 表,字段是 title、content、tags、created_at”,它就能生成一个包含这些字段的列表页和详情页模板。生成出来的模板通常比较朴素,但结构是对的。你只需要在它的基础上调整 CSS 样式、加上导航栏、调整布局就行。
我一般会保留 WorkBuddy 生成的模板结构,只改static目录下的 CSS 文件。这样下次重新生成模板时,样式不会丢。模板里用 Jinja2 语法来循环和判断:
{% for post in posts %} <div class="post-item"> <h2><a href="{{ url_for('detail', post_id=post[0]) }}">{{ post[1] }}</a></h2> <span class="date">{{ post[3] }}</span> </div> {% endfor %}4.4 日更流程的自动化脚本
日更的核心痛点是“每天都要手动操作一遍”。为了减少重复劳动,我写了一个简单的 Python 脚本,用命令行参数传入标题和内容,自动写入数据库:
import sqlite3 import sys from datetime import datetime def add_post(title, content, tags=''): conn = sqlite3.connect('instance/site.db') cursor = conn.cursor() cursor.execute( 'INSERT INTO posts (title, content, tags, status, created_at) VALUES (?, ?, ?, ?, ?)', (title, content, tags, 'published', datetime.now().strftime('%Y-%m-%d %H:%M:%S')) ) conn.commit() conn.close() print(f'已发布: {title}') if __name__ == '__main__': add_post(sys.argv[1], sys.argv[2], sys.argv[3] if len(sys.argv) > 3 else '')用的时候直接:
python add_post.py "今日标题" "今日正文内容" "标签1,标签2"这个脚本配合 WorkBuddy 的自定义指令功能,可以进一步简化。比如在 WorkBuddy 里设置一个指令,输入标题和内容后自动调用这个脚本并刷新页面。
5. 部署与日常维护:让站点稳定跑起来
5.1 本地部署与局域网访问
开发阶段用app.run(debug=True)就够了,但它默认只监听127.0.0.1,也就是只有本机能访问。如果你想让局域网内的其他设备也能访问,需要改成:
app.run(host='0.0.0.0', port=5000, debug=True)这样同一网络下的手机、平板就能通过你的电脑 IP 访问了。但要注意,debug=True在生产环境下必须关掉,因为它会暴露调试信息,有安全风险。
5.2 生产环境下的启动方式
生产环境建议用 gunicorn 或 waitress 来启动 Flask 应用。gunicorn 在 Linux/macOS 上表现很好:
gunicorn -w 1 -b 0.0.0.0:5000 app:app注意这里-w 1表示只用一个 worker 进程,这是为了避免 SQLite 的写入冲突。waitress 则是 Windows 上的好选择:
waitress-serve --listen=0.0.0.0:5000 app:app这两个命令都会让应用在后台稳定运行,不会因为终端关闭而停止。
5.3 数据备份与迁移的实操方法
备份就是复制.db文件。迁移的话,把整个项目目录打包带走就行,包括app.py、templates、static和instance目录。到了新机器上,装好 Python 和依赖,直接运行就能恢复。SQLite 的这种“文件即数据库”的特性,让迁移变得极其简单。
但有一个坑要注意:不同操作系统下的路径分隔符不同。如果你在 Windows 上开发,然后迁移到 Linux 上,代码里的路径要用os.path.join来拼接,不要硬编码反斜杠。
5.4 常见故障排查速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
启动报错ModuleNotFoundError: No module named 'flask' | 虚拟环境没激活或 Flask 没装 | 激活虚拟环境后重新pip install flask |
页面显示Internal Server Error | 代码有异常 | 查看终端报错信息,定位到具体行 |
| 数据库写入后查不到数据 | 没有commit() | 在execute后加上conn.commit() |
| 数据库被锁定 | 多个进程同时写入 | 确保只有一个进程在写,或改用 WAL 模式 |
| 模板找不到 | templates目录位置不对 | 确保templates在项目根目录下 |
| 静态文件 404 | static目录位置不对或路径写错 | 用url_for('static', filename='...')生成路径 |
提示:SQLite 的 WAL 模式可以提升并发读的性能,开启方式是在连接后执行
PRAGMA journal_mode=WAL;。对于日更站点,这个优化不是必须的,但开了也没坏处。
6. 我踩过的坑和实测有效的经验
6.1 数据库连接忘记关闭导致的问题
最开始写代码的时候,我经常忘记conn.close()。短时间看不出问题,但跑久了之后,数据库文件会被锁定,新的写入操作全部失败。后来我养成了一个习惯:用with语句来管理数据库连接:
with sqlite3.connect(DB_PATH) as conn: cursor = conn.cursor() cursor.execute(...)with语句会在代码块结束时自动提交并关闭连接,省心很多。但要注意,with只保证提交,不保证关闭。更稳妥的做法是配合contextlib.closing使用。
6.2 中文内容在 SQLite 中的编码问题
SQLite 默认使用 UTF-8 编码,存中文没有问题。但如果你在 Windows 上用命令行工具查看数据库,可能会看到乱码。这不是数据库的问题,是终端编码的问题。用 DB Browser 查看就正常了。另外,在 Python 里连接数据库时,确保文件是以 UTF-8 打开的,不要用gbk之类的编码。
6.3 WorkBuddy 生成代码后的必要检查项
WorkBuddy 生成的代码质量整体不错,但有几个地方我每次都会检查:数据库路径是否正确、路由函数名是否重复、模板变量名是否和视图函数传的一致。特别是变量名,WorkBuddy 有时候会生成post_list但模板里写的是posts,这种不一致会导致页面渲染失败。花两分钟检查一遍,比出了错再回头找要快得多。
6.4 日更习惯的维持技巧
技术问题解决之后,最大的挑战其实是“坚持每天更新”。我的经验是:把发布流程缩短到 3 分钟以内。如果每次发布都要打开编辑器、改代码、重启服务,那肯定坚持不下去。用前面说的命令行脚本,配合 WorkBuddy 的快捷指令,可以把发布变成“输入标题、输入内容、回车”三步。另外,提前准备好一周的素材,不要等到当天才想写什么。素材可以是读书笔记、工作复盘、看到的好文章摘录,任何你觉得有价值的东西都可以。
6.5 从单机到多端同步的扩展思路
如果你在多台设备上工作,想把 SQLite 数据库同步起来,最简单的办法是用云盘同步instance目录。但要注意,云盘同步和 SQLite 写入同时进行时可能会冲突。更稳妥的做法是写一个简单的同步脚本,在每次发布后把.db文件上传到云盘,在其他设备上手动下载覆盖。或者干脆把数据库放在一台常开的机器上,其他设备通过局域网访问 Flask 服务。
这个站点后续还可以扩展的方向很多:加一个搜索功能、加 RSS 输出、加标签筛选、加评论模块。但我的建议是先把日更跑通一个月,再考虑加功能。很多站点不是死于功能太少,而是死于维护者坚持不下去。