Flask实战:从零开发个人记账系统(数据库、图表、部署全解析)
系列教程写到第 11 章,终于轮到综合实战项目了。前面的 Python 基础、数据库、Web 框架、前端模板,学的都是零件;这一章我们要把这些零件组装成一台能正经跑起来的小机器——一个支持注册登录、收支记账、月度统计图表和预算提醒的个人记账系统。它不是一个玩具 Demo,而是我日常真正在用的项目,跑起来之后稳定迭代了几个月的那种。这篇文章写给两种人:一种是跟着本系列一路学到这里、想看看所有知识怎么串起来的读者;另一种是掌握了零散技术点、但一动手就不知道从哪开始的人。我会直接给你一份能落地的完整方案,从需求拆解、建表到写接口、画图表,最后部署上线,每一层都讲清楚为什么这样做。
1. 项目定位:记账应用为什么是综合实战的首选
很多教程最后的实战项目喜欢做博客系统和商城系统,我偏偏选了记账本。原因是记账应用的信息结构非常接近真实业务:有用户权限区分,有核心实体的增删改查,有按月维度的聚合统计,还有“预算-实际”这种需要跨表计算的逻辑。比起博客,它多了一层数字精确性;比起商城,它砍掉了订单、库存、支付这些噪音,让你能把精力集中在最核心的代码组织能力上。
1.1 需求拆解:从一句话需求到功能清单
拿到项目需求时,第一件事不是写代码,而是把模糊的一句话拆成可执行的功能点。这本项目的原始需求只有一句话:做一个个人记账网站,用户注册登录后可以记录收入和支出,按月查看统计图表。
我把它拆成了下面这份清单:
- 用户模块:注册、登录、注销;密码哈希存储;登录后的会话保持
- 账目模块:新增、编辑、删除收支记录;字段包括金额、分类、备注、发生日期
- 分类模块:内置常用分类(餐饮、交通、工资等),允许用户添加自定义分类
- 统计模块:月度总收入、总支出、结余;支出分类占比;近六个月收支趋势图
- 预算模块:用户每月给某个分类设定预算,超支后在首页提示
- 基础体验:桌面和手机都能正常使用,表单有前端校验,删除有二次确认
功能边界同样重要。我刻意砍掉了账单导入、多人协作、语音记账、定时提醒这类功能。综合实战项目最怕贪多,前十大章的知识点覆盖完就够了。你学的是整合能力,不是堆功能的能力。
1.2 技术栈选型:Flask + SQLAlchemy + Jinja2 背后的取舍
技术选型上没有用目前流行的前后端分离,而是采用了 Flask + SQLAlchemy + Jinja2 服务端渲染组合。这不是因为我不会写 Vue,而是综合实战阶段有更重要的东西要练:把业务逻辑写清楚、把数据关系理清楚。服务端渲染让每一个页面数据都能追溯到后端视图函数,中间少了一层 API 联调,学习曲线平缓得多。
具体到每个组件:
- Flask:路由和视图代码足够直观,生态成熟,遇到问题搜得到答案
- SQLAlchemy:用 ORM 管理模型和迁移,大部分时候不用手写 SQL,但需要时也能直接执行原生 SQL 做统计
- Jinja2:和 Flask 配合天然紧密,循环、继承、宏都能派上用场
- SQLite:开发环境直接用,零配置
- PostgreSQL:生产环境使用,通过环境变量切换连接串
- Bootstrap 5 + Chart.js:样式和图表都用现成库,省时间,聚焦业务
注意:选型没有绝对标准,但综合实战项目有一条铁律——每个技术选型都要能说明白理由。面试或者复盘的时候,这是区分“会用”和“懂用”的关键。
1.3 项目目录结构:动手前先画好地图
项目开始前把目录组织好,后面几十天的开发会舒服很多。这是我反复调优后的结构:
我把路由、模型和业务逻辑拆成了三个目录。日常开发里我见过太多路由函数里塞两百行代码的项目,维护起来能让人当场崩溃。views 目录里的函数只做三件事:接收请求参数、调用 services 里的方法、决定返回什么页面或 JSON。真正复杂的统计逻辑放到 services,模型只负责定义字段关系和简单的查询方法。这样拆完后,你调试一个算错账的问题时,不需要在一堆 @app.route 装饰器之间翻来翻去。
2. 数据库设计:先把底子打牢,再谈增删改查
综合实战项目的数据库设计,决定了后面所有代码的复杂度。记账系统表不多,但每张表之间都有外键关联,设计时稍有疏忽,写统计 SQL 的时候就要加班。
2.1 四张核心表的字段设计
整个系统只需要四张表:用户表、账目表、分类表、预算表。
用户表(users):
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer PK | 主键 |
| username | String(80) Unique | 用户名 |
| String(120) Unique | 登录邮箱 | |
| password_hash | String(256) | 哈希密码,永远不存明文 |
| created_at | DateTime | 注册时间 |
账目表(transactions):
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer PK | 主键 |
| user_id | Integer FK | 所属用户 |
| type | String(10) | income 或 expense |
| amount | Numeric(10, 2) | 金额,保留两位小数 |
| category_id | Integer FK | 分类 |
| note | String(255) | 备注 |
| transaction_date | Date | 发生日期 |
| is_deleted | Boolean | 软删除标记 |
| created_at | DateTime | 创建时间 |
分类表(categories):id、user_id(为空表示系统内置分类)、name、icon、sort_order。
预算表(budgets):id、user_id、category_id、month(格式 2025-04)、amount_limit。
这里有三个设计细节值得专门说。第一,金额字段必须用 Numeric(10, 2),不能用 Float。浮点数的二进制存储会导致 0.1 + 0.2 不等于 0.3 这种问题,做财务相关的东西碰到这种精度错误非常崩溃。第二,账目表里的 type 字段只有两个值,用字符串没问题,但如果以后要扩展更多类型,可以提前考虑枚举。第三,预算表的 month 字段直接存 `YY
相关推荐
基于Python+Open CV的手势识别算法设计
伴随着人工智能时代的到来,人机交互的领域也逐渐成为研究的一大方向;其中,手势识别是人机交互领域的一项关键技术,自此手势识别也迎来了一波高潮,近几年无论是在消费领域、电子领域、数码领域、家电领域甚至汽车领域上,都能或多或少的见到手势识别的身影。 手势识别在设计智能高效的人机界面方面具有至关重要的作用, 目前手势识别已应用到手语识别、智能监控、到虚拟现实等各个领域,手势识别的原理都是利用各种传感器(例如红外、摄像头等)对手部的形态进行捕捉并进行建模,形成一个模型信息的序列帧,而后将这些信息序列转换为机器能够识别的相对应指令(例如打开、切换菜单、移动等)来完成控制。 采用Python的集成开发环境Pycharm进行本次课程设计,在Pycharm中进行需要库(模块)的下载,调取电脑摄像头,按帧读取摄像头采集到的头像,形态学处理,图像旋转(由于摄像头采集到的图像是镜像,需要用cv2.flip将摄像头采集到的图像进行处理),选取图片中固定位置作为手势输入,用红线画出手势识别框,基于hsv的肤色检测,进行高斯滤波,找出轮廓,求出图像中手势的凹凸点,手指间角度求取。
ROS-CV-ImageConverter:将ROS图像转换为OpenCV(cv :: Mat)类型的图像
ROS-CV图像转换器 依存关系 cv_bridge(ROS软件包)
计算机视觉图像处理-CV2与图像插值算法
用最近邻插值与双线性插值原理完成图像缩放 最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输。缺点:使用最近邻插值算法处理图像放大时,在图象中可能出现明显的块状效应 双线性插值,在两个方向上做三次线性插值。使用双线性插值算法处理图像放大时,在图象中可能出现马赛克 代码 import cv2 img = cv2.imread(’./xiabang.jpg’, cv2.IMREAD_UNCHANGED) #缩放比例 scale_percent = 0.3 width = int(img.shape[1] * scale_percent) height = int
基于水平集CV模型的图像分割(Matlab代码)
基于水平集CV模型的图像分割(Matlab代码),全套代码
导向滤波(guide_filter)的python实现
导向滤波(guide_filter)的python实现,可以结合暗通道;理论实现比较好的图像去噪效果。

