量力而行” 原则

确定需求后,我花了两天时间查资料、选技术栈。核心原则只有一个:用自己熟悉的技术,优先保证 “能跑通”,再追求 “做得好”

1. 后端:Python + Flask

一开始我纠结过用 Django 还是 Flask。Django 功能全面,自带后台管理系统,但我看了文档后发现,它的 “大而全” 对小项目来说反而有点冗余 —— 我只需要简单的 CRUD(增删改查)接口,不需要用户认证、权限管理这些复杂功能。而 Flask 是轻量级框架,没有固定的项目结构,上手快,还能灵活搭配扩展库,非常适合新手做小项目。

2. 前端:Bootstrap + 原生 JS

前端是我的短板,只会写简单的 HTML/CSS。为了避免界面太丑,我直接用了 Bootstrap—— 它的栅格系统和组件库(比如按钮、卡片、表单)能快速搭出整洁的界面,不用自己写复杂的样式。交互逻辑方面,只用原生 JS 实现了 “添加任务”“切换状态”“删除任务” 等基础功能,没有引入 Vue、React 这些框架,减少学习成本。

3. 数据库:SQLite

任务数据需要本地存储,我选择了 SQLite。它不需要单独安装数据库服务,数据直接存在一个.db 文件里,对新手友好,而且 Flask 的扩展库 SQLAlchemy 能轻松实现数据库操作,不用手写 SQL 语句。

4. 最终技术栈清单

模块 技术选择 选择理由
后端框架 Flask 轻量、上手快,适合小项目
数据库 SQLite + SQLAlchemy 本地存储,无需额外服务,操作简单
前端 UI Bootstrap 5 快速搭建整洁界面,减少 CSS 工作量
交互逻辑 原生 JavaScript 满足基础功能,避免学习新框架
部署 / 打包 PyInstaller 可将 Python 脚本打包成 exe,双击运行

三、开发过程:踩过的坑比写的代码还多

从搭建环境到实现核心功能,我花了整整两周时间。每天晚上抽 2-3 小时开发,过程中遇到的问题远比想象中多,但每解决一个 bug,都能明显感觉到自己的进步。

1. 第一步:搭建项目结构(最开始的 “混乱期”)

一开始我没规划项目结构,所有代码都写在一个 app.py 文件里,结果不到 300 行代码就乱得像 “一锅粥”。后来查资料发现,Flask 项目虽然灵活,但也需要合理的目录划分。最终我整理出这样的结构:

TaskFlow/
├── app.py          # 入口文件(初始化Flask、注册路由)
├── models/         # 数据库模型
│   └── task.py     # 任务表定义
├── routes/         # 接口路由
│   └── task_routes.py # 任务相关接口(增删改查)
├── static/         # 静态文件(CSS、JS、图片)
│   ├── css/
│   └── js/
├── templates/      # 前端页面
│   └── index.html  # 主界面
├── instance/       # SQLite数据库文件
│   └── taskflow.db
└── requirements.txt # 依赖库清单

这个结构虽然简单,但能让代码各司其职,后面维护起来轻松多了。

2. 核心功能实现:从 “能跑通” 到 “能用好”

(1)数据库模型:定义任务的 “骨架”

首先要确定任务需要包含哪些字段。根据我的需求,任务应该有标题、详情、状态(待办 / 进行中 / 已完成)、截止时间、创建时间。用 SQLAlchemy 定义模型的代码如下:

# models/task.py
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

class Task(db.Model):
    # 主键ID
    id = db.Column(db.Integer, primary_key=True)
    # 任务标题(不能为空)
    title = db.Column(db.String(100), nullable=False)
    # 任务详情(可选)
    content = db.Column(db.Text, nullable=True)
    # 任务状态:todo(待办)、doing(进行中)、done(已完成)
    status = db.Column(db.Enum('todo', 'doing', 'done'), default='todo')
    # 截止时间(可选)
    deadline = db.Column(db.DateTime, nullable=True)
    # 创建时间(自动生成)
    create_time = db.Column(db.DateTime, default=datetime.utcnow)

    def to_dict(self):
        """将模型转为字典,方便前端接收数据"""
        return {
            'id': self.id,
            'title': self.title,
            'content': self.content,
            'status': self.status,
            'deadline': self.deadline.strftime('%Y-%m-%d %H:%M') if self.deadline else None,
            'create_time': self.create_time.strftime('%Y-%m-%d %H:%M')
        }

这里有个小坑:datetime 类型的数据不能直接传给前端,需要用 strftime 转为字符串格式,否则会报错。

(2)接口开发:实现任务的 “增删改查”

以 “添加任务” 接口为例,我需要接收前端传来的标题、详情、截止时间,验证参数后存入数据库。代码如下:

# routes/task_routes.py
from flask import Blueprint, request, jsonify
from models.task import db, Task
from datetime import datetime

# 创建蓝图(类似路由分组)
task_bp = Blueprint('task', __name__)

@task_bp.route('/api/tasks', methods=['POST'])
def add_task():
    """添加新任务"""
    # 接收前端传来的JSON数据
    data = request.get_json()
    
    # 验证参数:标题不能为空
    if not data.get('title'):
        return jsonify({'code': 400, 'msg': '任务标题不能为空!'}), 400
    
    # 处理截止时间:前端传的是字符串,需要转为datetime类型
    deadline_str = data.get('deadline')
    deadline = None
    if deadline_str:
        try:
            deadline = datetime.strptime(deadline_str, '%Y-%m-%d %H:%M')
        except ValueError:
            return jsonify({'code': 400, 'msg': '截止时间格式错误(需为YYYY-MM-DD HH:MM)!'}), 400
    
    # 创建任务实例
    new_task = Task(
        title=data.get('title'),
        content=data.get('content'),
        deadline=deadline
    )
    
    # 存入数据库
    try:
        db.session.add(new_task)
        db.session.commit()
        return jsonify({
            'code': 200, 
            'msg': '任务添加成功!', 
            'data': new_task.to_dict()
        }), 200
    except Exception as e:
        # 出错时回滚
        db.session.rollback()
        return jsonify({'code': 500, 'msg': f'添加失败:{str(e)}'}), 500

这个接口我调试了好几次:第一次是忘记处理截止时间的格式,导致数据库报错;第二次是没加异常捕获,一旦参数错误,整个程序就崩溃了。后来加上了参数验证和 try-except,才终于稳定运行。

(3)前端界面:从 “能用” 到 “顺眼”

前端页面的核心是 “任务列表” 和 “添加任务表单”。我用 Bootstrap 的卡片组件展示任务,不同状态的任务用不同颜色标记(待办:灰色、进行中:蓝色、已完成:绿色),还加了 “截止时间提醒”—— 如果任务超时未完成,标题会显示红色并加下划线。

主界面的效果如图 1 所示(实际使用时可替换为真实截图):图 1:TaskFlow 主界面

  • 左侧:任务列表,按状态分组(待办 / 进行中 / 已完成),每个任务卡片显示标题、截止时间、创建时间,底部有 “编辑”“删除”“切换状态” 按钮。
  • 右侧:添加 / 编辑任务表单,包含 “标题”“详情”“截止时间” 三个字段,点击 “提交” 按钮后,通过 JS 调用后端接口,无需刷新页面就能更新任务。

这里有个小技巧:为了实现 “无刷新更新任务”,我用了 JS 的 fetch API 调用后端接口,成功后直接修改 DOM 元素,不用跳转页面,体验更流畅。

3. 踩过的 “经典新手坑”

开发过程中,有几个 bug 让我印象特别深,现在回想起来还觉得好笑:

  • 坑 1:跨域问题。一开始我把前端页面直接打开(file:// 协议),调用后端接口时一直报错 “Access to fetch at 'http://localhost:5000/api/tasks' from origin 'null' has been blocked by CORS policy”。后来查资料才知道,这是跨域问题,需要在 Flask 中安装flask-cors扩展,添加一行CORS(task_bp)就能解决。
  • 坑 2:数据库路径错误。我一开始把 SQLite 数据库文件放在项目根目录,结果用 PyInstaller 打包后,程序找不到数据库文件。后来才明白,Flask 的instance文件夹是专门用来存放实例化数据的,把.db 文件放在这里,打包后能自动找到路径。
  • 坑 3:时间时区问题。数据库存储的是 UTC 时间,前端显示时比本地时间少 8 小时(我在东八区)。最后在to_dict方法里把时间转为本地时区,才解决了这个问题。

四、开源:从 “自己用” 到 “分享给别人”

当 TaskFlow 能稳定运行,满足我的日常需求后,朋友问我:“能不能发我一份?我也想用。” 这让我萌生了 “开源” 的想法 —— 既然这个工具对我有用,说不定对其他新手也有帮助,而且开源还能得到别人的反馈,帮我改进项目。

1. 开源前的准备工作

我花了 3 天时间做开源准备,核心是 “让别人能看懂、能用上”:

(1)写一份详细的 README.md

README 是项目的 “说明书”,我按照 GitHub 上的优质项目模板,写了以下内容:

  • 项目介绍:TaskFlow 是什么,适合谁用,核心功能有哪些。
  • 安装步骤:分两种方式 —— 源码运行(需要安装 Python 和依赖库)、直接下载 exe 文件(适合不懂编程的用户)。
  • 使用方法:配了 3 张截图,分别说明 “添加任务”“切换任务状态”“编辑 / 删除任务” 的操作。
  • 贡献指南:告诉别人如果想改代码、加功能,应该怎么提交 PR(比如先 fork 仓库,再创建分支,最后提交 PR),还写了简单的代码规范(比如变量名用小写下划线,函数名首字母小写)。
  • 许可证:选择了 MIT 许可证 —— 这是最宽松的开源许可证之一,允许别人自由使用、修改、分发,只要保留版权声明即可,很适合新手项目。
(2)配置.gitignore

为了避免把不必要的文件(比如虚拟环境、IDE 配置文件、数据库日志)提交到 GitHub,我在项目根目录添加了.gitignore 文件,直接用了 GitHub 官方的 Python.gitignore 模板,再加上自己项目的特殊文件(比如 instance 文件夹下的.db 文件,避免把自己的任务数据传上去)。

(3)测试 “一键运行”

我用 PyInstaller 把项目打包成 exe 文件,测试了在 Windows 10 和 Windows 11 上的运行情况,确保别人下载后双击就能打开,不用配置环境。还在 README 里写了 “常见问题”,比如 “exe 文件打不开怎么办”“数据库文件丢失了怎么恢复”。

2. 第一次提交:紧张又期待

2023 年 12 月 25 日,我在 GitHub 上创建了仓库,命名为 “TaskFlow-Light”,然后用 Git 命令把代码提交上去。点击 “Push” 按钮时,我的手都有点抖 —— 担心代码写得太烂,被别人嘲笑;又期待有人能看到这个项目,给我提建议。

提交成功后,我把项目分享到了学校的编程交流群和几个新手开发者社区。第一天没有任何动静,我有点失落;第二天早上打开 GitHub,突然看到一条通知:有人给我的项目点了 “Star”!那是我的第一个 Star,虽然只有一个,但我兴奋得差点跳起来。

后来,陆续有几个人提了 issue:有人说 “希望能导出任务为 Excel”,有人反馈 “切换任务状态时偶尔会卡顿”,还有一个大二的学弟提交了第一个 PR—— 他修复了前端表单的一个输入验证 bug,还加了 “任务搜索” 功能。

处理这些 issue 和 PR 的过程,比我自己开发时学到的还多。比如有人问 “能不能支持 Mac 系统”,我虽然没接触过 Mac 打包,但查了资料后,在 README 里补充了 Mac 下的运行方法;学弟提交的 PR 里用了我没学过的 JS 方法,我跟着他的代码学了半天,还学会了如何用 GitHub 的 “Review PR” 功能给出反馈。

五、总结:开源不是终点,而是新的起点

现在,TaskFlow 的 GitHub 仓库有了 23 个 Star,收到了 8 个 PR,解决了 15 个 issue。虽然和那些热门项目比起来微不足道,但对我来说,这个项目的意义远超 “一个任务工具”—— 它让我从 “只会跟着教程写代码” 的新手,变成了 “能独立解决问题、还能分享给别人” 的开发者。

回顾整个过程,我有三个最深的感悟:

  1. “完成” 比 “完美” 更重要。我的代码肯定有很多不规范的地方,界面也不够精致,但如果我一开始就追求 “写得和专业项目一样好”,可能至今都不会提交第一行代码。开源的第一步,是先把 “能用的版本” 放出来,再慢慢迭代。
  2. 开源是最好的学习方式。别人的 issue 和 PR 会逼着你去查资料、学新东西,比如为了支持 Excel 导出,我学会了用 Python 的 openpyxl 库;为了修复卡顿问题,我优化了数据库查询语句。这种 “带着问题学” 的效率,比单纯看教程高太多。
  3. 新手也能为开源做贡献。我以前觉得开源是大佬的事,后来发现,哪怕是修复一个小 bug、补充一句文档、提一个合理的需求,都是对项目的帮助。每个大佬都是从新手过来的,开源社区需要的是 “愿意分享、愿意学习” 的态度,而不是完美的代码。

现在,我正在给 TaskFlow 加 “云同步” 功能(用 Flask+Redis 实现),还打算学习 Vue,重构前端界面。我的第一个开源项目已经告一段落,但我的开源之路才刚刚开始。

如果你也是编程新手,不妨从 “解决自己的一个小痛点” 开始,写一个简单的工具,然后尝试开源。说不定你会和我一样,在这个过程中收获意想不到的成长。

图 2:TaskFlow 的 GitHub 仓库首页(实际使用时可替换为真实截图,显示 Star 数、Fork 数、最近提交记录)图 3:第一个 PR 的审核记录(实际使用时可替换为真实截图,显示 PR 的提交内容、审核反馈、合并记录)

如果需要进一步完善这篇文章,比如补充具体的代码调试步骤、添加更多项目截图,或者想生成一份 “TaskFlow 开发日志”(记录每天的开发进度和问题),我可以帮你整理一份TaskFlow 开源项目实战手册,方便你作为新手开发参考。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐