Python实现的大学生生活费记账与数据分析工具
Python实现的大学生生活费记账与数据分析工具
完整代码链接:https://pan.quark.cn/s/b1beb34865c9
一、项目背景与意义
1.1 项目背景
大学生群体普遍面临生活费管理的困惑:每月的生活费花在哪里了?食堂、外卖、交通、购物、娱乐……每一笔看似不大的开支,月末汇总时却常常超支。传统的记账方式(手写记录或手机备忘录)存在记录不便、统计困难、缺乏分析等问题,难以帮助大学生真正掌握自己的消费状况。
随着Web技术的普及,基于浏览器的在线记账工具成为一种理想的解决方案。本项目立足于大学生实际需求,设计并实现一套功能完整的记账与数据分析工具,帮助大学生轻松记录日常收支、直观了解消费结构、合理规划生活预算。
1.2 项目意义
- 实用价值:为大学生提供简单易用的记账工具,培养良好的理财习惯
- 数据分析能力:通过可视化图表呈现消费数据,帮助用户发现消费模式和优化空间
- 技术综合实践:涉及Flask Web开发、SQLAlchemy ORM、ECharts可视化、RESTful API等多项技术
- 毕设参考价值:项目结构完整、功能链闭环,覆盖数据采集(录入)、存储、处理、分析、展示全流程
实际演示界面




二、系统需求分析
2.1 功能需求
(1)用户管理
- 用户注册与登录
- 密码加密存储
(2)账单记录
- 记一笔:选择类型(支出/收入)、分类、输入金额和备注
- 账单列表:分页展示,按类型、分类、月份筛选
- 编辑和删除账单
(3)分类管理
- 支出分类:餐饮、交通、购物、娱乐等
- 收入分类:生活费、兼职、红包等
- 支持自定义添加和删除分类
(4)预算管理
- 设置每月生活费总额
- 按支出分类设置预算额度
- 预算执行进度展示
(5)数据分析
- 每日支出趋势图
- 支出分类占比环形图
- 月度支出趋势折线图
- 预算执行统计
- 收支结余概览
2.2 非功能需求
- 界面美观:绿色渐变主题,响应式布局
- 操作流畅:表单即时验证,AJAX动态加载分类
- 数据安全:密码哈希存储,登录会话管理
- 轻量易部署:SQLite数据库,无需额外配置
三、系统设计
3.1 系统架构
采用B/S三层架构:
- 表现层:Bootstrap + ECharts,Jinja2模板引擎
- 业务逻辑层:Flask路由分发,WTForms表单验证
- 数据访问层:SQLAlchemy ORM,SQLite数据库
3.2 功能模块
| 模块 | 功能 |
|---|---|
| 用户模块 | 注册、登录、退出、会话管理 |
| 仪表盘 | 收支概览、每日趋势图、分类占比图、最近记录 |
| 账单管理 | 增删改查、按类型/分类/月份筛选 |
| 分类管理 | 支出/收入分类维护 |
| 预算管理 | 月总预算、分类预算设置与进度跟踪 |
| 数据分析 | 日趋势、分类占比、月趋势、预算执行 |
3.3 数据库设计
系统使用SQLite,共4张核心表。
用户表(users)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| username | String(64) | 用户名,唯一 |
| password_hash | String(256) | 密码哈希 |
| monthly_budget | Float | 月生活费预算 |
| created_at | DateTime | 创建时间 |
分类表(categories)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| name | String(50) | 分类名称 |
| icon | String(20) | FontAwesome图标 |
| type | String(10) | income/expense |
| user_id | Integer | 外键→users |
账单表(transactions)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| user_id | Integer | 外键→users |
| category_id | Integer | 外键→categories |
| amount | Float | 金额 |
| type | String(10) | income/expense |
| note | String(200) | 备注 |
| date | Date | 日期 |
| created_at | DateTime | 创建时间 |
预算表(budgets)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | Integer | 主键 |
| user_id | Integer | 外键→users |
| category_id | Integer | 外键→categories |
| month | String(7) | 月份,格式2024-01 |
| amount | Float | 预算金额 |
3.4 实体关系(ER图)
- 用户与账单:一对多
- 用户与分类:一对多
- 用户与预算:一对多
- 分类与账单:一对多
- 分类与预算:一对多
四、系统实现
4.1 项目结构
Python实现的大学生生活费记账与数据分析工具/
├── app.py # 主应用(路由+启动)
├── config.py # 配置
├── models.py # 数据模型
├── forms.py # WTForms表单
├── requirements.txt # 依赖
├── static/css/style.css
├── static/js/main.js
└── templates/
├── base.html # 基础模板
├── login.html # 登录
├── register.html # 注册
├── dashboard.html # 仪表盘
├── transactions/ # 账单
├── categories/ # 分类
├── budget/ # 预算
└── analysis.html # 分析
4.2 技术选型
| 技术 | 版本 | 用途 |
|---|---|---|
| Python | 3.8+ | 开发语言 |
| Flask | 2.3.3 | Web框架 |
| Flask-SQLAlchemy | 3.1.1 | ORM |
| Flask-Login | 0.6.3 | 登录管理 |
| Flask-WTF | 1.2.1 | 表单+CSRF |
| Bootstrap | 5.3.2 | UI框架 |
| ECharts | 5.4.3 | 图表可视化 |
4.3 核心代码实现
4.3.1 数据模型(models.py)
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
db = SQLAlchemy()
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, nullable=False, index=True)
password_hash = db.Column(db.String(256), nullable=False)
monthly_budget = db.Column(db.Float, default=2000.0)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
transactions = db.relationship('Transaction', backref='user', lazy='dynamic')
categories = db.relationship('Category', backref='user', lazy='dynamic')
budgets = db.relationship('Budget', backref='user', lazy='dynamic')
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Category(db.Model):
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
icon = db.Column(db.String(20), default='tag')
type = db.Column(db.String(10), nullable=False) # income / expense
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
transactions = db.relationship('Transaction', backref='category', lazy='dynamic')
budgets = db.relationship('Budget', backref='category', lazy='dynamic')
class Transaction(db.Model):
__tablename__ = 'transactions'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
amount = db.Column(db.Float, nullable=False)
type = db.Column(db.String(10), nullable=False)
note = db.Column(db.String(200))
date = db.Column(db.Date, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
class Budget(db.Model):
__tablename__ = 'budgets'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
month = db.Column(db.String(7), nullable=False)
amount = db.Column(db.Float, nullable=False)
关键设计要点:
UserMixin提供了Flask-Login所需的用户会话方法backref建立了模型间的双向关系,如Transaction.user可获取账单对应的用户对象lazy='dynamic'表示延迟加载,只有在调用.all()或.count()时才执行查询
4.3.2 仪表盘聚合查询(app.py)
仪表盘是系统的核心页面,需要在一次请求中完成多项统计查询:
@app.route('/')
@login_required
def dashboard():
today = date.today()
first_day = today.replace(day=1)
if today.month == 12:
next_month = today.replace(year=today.year + 1, month=1)
else:
next_month = today.replace(month=today.month + 1)
# 本月支出
month_expense = db.session.query(func.sum(Transaction.amount)).filter(
Transaction.user_id == current_user.id,
Transaction.type == 'expense',
Transaction.date >= first_day,
Transaction.date < next_month
).scalar() or 0
# 本月每日支出趋势
monthly_data = db.session.query(
func.strftime('%Y-%m-%d', Transaction.date).label('day'),
func.sum(Transaction.amount).label('total')
).filter(
Transaction.user_id == current_user.id,
Transaction.type == 'expense',
Transaction.date >= first_day,
Transaction.date < next_month
).group_by('day').order_by('day').all()
# 本月支出分类排名
top_categories = db.session.query(
Category.name, Category.icon,
func.sum(Transaction.amount).label('total')
).join(Transaction, Category.id == Transaction.category_id
).filter(
Transaction.user_id == current_user.id,
Transaction.type == 'expense',
Transaction.date >= first_day,
Transaction.date < next_month
).group_by(Category.id).order_by(func.sum(Transaction.amount).desc()).all()
...
这里使用了SQLAlchemy的聚合函数:
func.sum()计算总和func.count()计数func.avg()求平均值func.strftime()SQLite日期格式化.scalar()返回单个值.group_by()分组统计
4.3.3 数据分析页面(analysis.html中的ECharts图表)
以每日支出柱状图为例:
echarts.init(document.getElementById('dailyChart')).setOption({
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: [...] },
yAxis: { type: 'value', axisLabel: { formatter: '¥{value}' } },
series: [{
type: 'bar',
data: [...],
itemStyle: {
color: {
type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: '#f093fb' },
{ offset: 1, color: '#f5576c' }
]
}
},
label: { show: true, position: 'top' }
}]
});
ECharts配置项说明:
tooltip鼠标悬停提示框xAxis/yAxis坐标轴配置,axisLabel.formatter格式化标签前缀series数据系列,itemStyle.color设置渐变色label数据标签,显示在柱状图上方
4.3.4 动态加载分类(AJAX)
在添加账单时,选择类型后自动加载对应的分类选项,提升用户体验:
@app.route('/api/categories/<typ>')
@login_required
def api_categories(typ):
cats = Category.query.filter_by(user_id=current_user.id, type=typ).all()
return jsonify([{'id': c.id, 'name': c.name, 'icon': c.icon} for c in cats])
function loadCategories() {
var type = document.querySelector('select[name="type"]').value;
fetch('/api/categories/' + type)
.then(function(r) { return r.json(); })
.then(function(data) {
var sel = document.querySelector('select[name="category_id"]');
sel.innerHTML = '';
data.forEach(function(c) {
var opt = document.createElement('option');
opt.value = c.id;
opt.text = c.name;
sel.appendChild(opt);
});
});
}
前端通过 fetch 调用后端的 RESTful 接口,获取JSON数据后动态更新下拉选择框,避免了页面刷新。
4.3.5 自动初始化默认分类
用户注册时自动创建常用的支出和收入分类,降低初次使用门槛:
def init_default_categories(user_id):
defaults = [
('餐饮', 'utensils', 'expense'), ('交通', 'car', 'expense'),
('购物', 'shopping-bag', 'expense'), ('娱乐', 'gamepad', 'expense'),
('学习', 'book', 'expense'), ('医疗', 'heartbeat', 'expense'),
('居住', 'home', 'expense'), ('服饰', 'tshirt', 'expense'),
('通讯', 'phone', 'expense'), ('其他支出', 'tag', 'expense'),
('生活费', 'dollar-sign', 'income'), ('兼职', 'briefcase', 'income'),
('红包', 'gift', 'income'), ('其他收入', 'tag', 'income'),
]
for name, icon, typ in defaults:
if not Category.query.filter_by(user_id=user_id, name=name, type=typ).first():
db.session.add(Category(name=name, icon=icon, type=typ, user_id=user_id))
db.session.commit()
4.3.6 注册路由
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
if User.query.filter_by(username=form.username.data).first():
flash('用户名已存在', 'danger')
return render_template('register.html', form=form)
user = User(username=form.username.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
init_default_categories(user.id) # 初始化默认分类
flash('注册成功,请登录', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
五、系统功能展示
5.1 注册登录页
绿色渐变主题,居中卡片布局。注册时带密码确认验证,登录后自动跳转仪表盘。新用户注册即自动创建14个默认分类,无需手动配置。
5.2 首页仪表盘
- 顶部概览卡片:本月支出、本月收入、本周支出、今日支出
- 每日支出趋势折线图:展示本月每日消费变化,面积填充增强视觉效果
- 支出分类占比环形图:各分类消费占比一目了然
- 预算概览:进度条展示预算使用情况,超80%变黄色,超100%变红色
- 最近记录:最近10条账单快速预览
5.3 账单管理
账单列表支持按类型(支出/收入)、分类、月份三个维度筛选。金额用红绿颜色区分支出和收入,表格含编辑和删除操作,分页展示。
5.4 记一笔
选择类型后通过AJAX动态加载对应分类,无需手动切换。默认日期为当天,支持填写备注。
5.5 分类管理
分支出和收入两栏展示,支持自定义添加分类(带FontAwesome图标选择器和类型选择),删除时检查是否已被账单引用。
5.6 预算管理
支持两类预算设置:
- 月总预算:在用户资料中设置每月生活费总额
- 分类预算:针对每个支出分类设置当月预算额度
5.7 数据分析
数据分析页面按月选择维度,展示:
- 关键指标:总支出、总收入、日均支出、结余
- 每日支出柱状图:渐变粉色柱状,标注金额
- 分类占比环形图:带百分比标签
- 月度趋势折线图:近12个月支出走势
- 预算执行表:进度条展示各分类预算完成情况
六、系统部署
6.1 环境要求
Python 3.8及以上版本,推荐使用虚拟环境。
6.2 安装依赖
在项目根目录执行:
pip install -r requirements.txt
依赖清单:
Flask==2.3.3
Flask-SQLAlchemy==3.1.1
Flask-Login==0.6.3
Flask-WTF==1.2.1
WTForms==3.1.1
Werkzeug==2.3.7
6.3 启动系统
python app.py
访问 http://127.0.0.1:5000,注册账号后即可开始使用。
七、总结与展望
7.1 项目总结
| 维度 | 成果 |
|---|---|
| 功能完整性 | 覆盖记账全流程:记录→分类→预算→分析 |
| 技术栈 | Flask + SQLAlchemy + ECharts + Bootstrap |
| 用户体验 | 绿色渐变UI、响应式布局、AJAX动态加载 |
| 数据安全 | Werkzeug密码加密、Flask-Login会话保护 |
7.2 不足与改进方向
- 数据持久化:SQLite适合单用户,多用户场景可迁移至MySQL
- 批量操作:可增加Excel导入导出功能,方便数据迁移
- 多端适配:可开发微信小程序版本,满足移动端记账需求
- 智能分析:引入机器学习算法,基于历史数据预测未来消费趋势
- 账单提醒:在预算超支时发送通知或邮件提醒
7.3 附录:完整代码清单
# config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY') or 'expense-tracker-secret-2024'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'expenses.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
WTF_CSRF_ENABLED = True
# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SelectField, FloatField, DateField, SubmitField
from wtforms.validators import DataRequired, Length, Optional, NumberRange, EqualTo
class LoginForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(1, 64)])
password = PasswordField('密码', validators=[DataRequired()])
submit = SubmitField('登录')
class RegisterForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(), Length(2, 64)])
password = PasswordField('密码', validators=[DataRequired(), Length(6, 128)])
confirm = PasswordField('确认密码', validators=[DataRequired(), EqualTo('password', message='两次密码不一致')])
submit = SubmitField('注册')
class TransactionForm(FlaskForm):
type = SelectField('类型', choices=[('expense', '支出'), ('income', '收入')])
category_id = SelectField('分类', coerce=int)
amount = FloatField('金额', validators=[DataRequired(), NumberRange(0.01, 999999)])
date = DateField('日期', format='%Y-%m-%d')
note = StringField('备注', validators=[Optional(), Length(0, 200)])
submit = SubmitField('保存')
class CategoryForm(FlaskForm):
name = StringField('分类名称', validators=[DataRequired(), Length(1, 50)])
type = SelectField('类型', choices=[('expense', '支出'), ('income', '收入')])
icon = SelectField('图标', choices=[
('utensils', '餐饮'), ('car', '交通'), ('shopping-bag', '购物'),
('gamepad', '娱乐'), ('book', '学习'), ('heartbeat', '医疗'),
('home', '居住'), ('tshirt', '服饰'), ('gift', '礼物'),
('phone', '通讯'), ('dollar-sign', '收入'), ('briefcase', '兼职'),
('piggy-bank', '储蓄'), ('coffee', '饮品'), ('film', '影视'),
('tag', '其他')
])
submit = SubmitField('保存')
class BudgetForm(FlaskForm):
category_id = SelectField('支出分类', coerce=int)
amount = FloatField('预算金额', validators=[DataRequired(), NumberRange(0.01, 999999)])
submit = SubmitField('设置预算')
class ProfileForm(FlaskForm):
monthly_budget = FloatField('月总预算', validators=[DataRequired(), NumberRange(0, 999999)])
submit = SubmitField('保存设置')
结语
本系统从大学生实际需求出发,设计并实现了一套完整的生活费记账与数据分析工具。通过Flask框架搭建后端,结合Bootstrap和ECharts构建前端界面,实现了从数据录入、存储、查询到统计分析的全流程闭环。项目代码结构清晰,注释完整,既可作为日常记账工具使用,也为计算机相关专业的毕业设计提供了可参考的完整案例。
更多推荐
所有评论(0)