1. 为什么选择SQLAlchemy构建命令行待办事项应用
十年前我刚接触Python时,曾用纯文本文件管理待办事项。直到某天文件损坏导致数据全失,才意识到需要更可靠的解决方案。SQLAlchemy作为Python生态中最成熟的ORM工具,完美解决了数据持久化问题,特别适合构建我们今天的命令行待办事项应用。
这个场景下SQLAlchemy有三大不可替代的优势:
- 数据库无关性:用SQLite开发,后期可无缝迁移到PostgreSQL
- 类型安全:强制字段类型检查,避免"买苹果"变成"买0个"的经典错误
- 事务支持:确保任务状态变更的原子性,不会出现"标记完成却未保存"的尴尬
提示:虽然SQLite适合个人使用,但若需要多设备同步,建议换用PostgreSQL+SSH隧道方案。我曾用这种架构为团队开发过协作版任务系统,日均处理2000+任务无压力。
2. 项目架构设计
2.1 核心数据模型设计
我们的待办事项应用需要三个核心模型:
python复制from datetime import datetime
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Task(Base):
__tablename__ = 'tasks'
id = Column(Integer, primary_key=True)
title = Column(String(100), nullable=False)
description = Column(String(500))
is_completed = Column(Boolean, default=False)
created_at = Column(DateTime, default=datetime.now)
due_date = Column(DateTime)
category_id = Column(Integer, ForeignKey('categories.id'))
category = relationship("Category", back_populates="tasks")
class Category(Base):
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
tasks = relationship("Task", back_populates="category")
class Tag(Base):
__tablename__ = 'tags'
id = Column(Integer, primary_key=True)
name = Column(String(30), unique=True)
这个设计考虑了实际使用场景:
due_date字段支持设置截止日期- 分类和标签系统方便任务组织
- 自动记录的创建时间有助于生成周报
2.2 数据库连接配置
开发阶段建议使用SQLite,部署时再考虑其他数据库:
python复制from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 开发配置
engine = create_engine('sqlite:///todo.db', echo=True)
SessionLocal = sessionmaker(bind=engine)
# 生产配置示例(PostgreSQL)
# engine = create_engine(
# "postgresql://user:password@localhost/todo",
# pool_size=10,
# max_overflow=20,
# pool_timeout=30
# )
注意:echo=True会在控制台打印SQL语句,非常适合调试,但生产环境务必关闭。
3. 核心功能实现
3.1 任务管理模块
python复制class TaskManager:
def __init__(self):
self.session = SessionLocal()
def add_task(self, title, description=None, due_date=None, category=None):
"""添加新任务"""
task = Task(
title=title,
description=description,
due_date=due_date,
category=category
)
self.session.add(task)
self.session.commit()
return task
def complete_task(self, task_id):
"""标记任务为已完成"""
task = self.session.query(Task).get(task_id)
if task:
task.is_completed = True
self.session.commit()
return True
return False
def list_tasks(self, show_completed=False):
"""列出任务"""
query = self.session.query(Task)
if not show_completed:
query = query.filter(Task.is_completed == False)
return query.order_by(Task.due_date).all()
避坑经验:
- 每次操作后记得commit,我曾因忘记提交导致数据"丢失"两小时
- 查询条件顺序会影响性能,先过滤再排序
- 返回查询对象而非结果列表,便于链式调用
3.2 分类与标签系统
python复制class CategoryManager:
def __init__(self):
self.session = SessionLocal()
def find_or_create(self, name):
"""查找或创建分类"""
category = self.session.query(Category).filter_by(name=name).first()
if not category:
category = Category(name=name)
self.session.add(category)
self.session.commit()
return category
class TagManager:
def __init__(self):
self.session = SessionLocal()
def tag_task(self, task_id, tag_names):
"""为任务添加标签"""
task = self.session.query(Task).get(task_id)
if not task:
return False
for name in tag_names:
tag = self.session.query(Tag).filter_by(name=name).first()
if not tag:
tag = Tag(name=name)
self.session.add(tag)
task.tags.append(tag)
self.session.commit()
return True
性能优化技巧:
- 使用
find_or_create模式避免重复分类 - 批量处理标签减少提交次数
- 建立索引加速名称查询
4. 命令行界面实现
4.1 使用argparse构建CLI
python复制import argparse
from datetime import datetime
def main():
parser = argparse.ArgumentParser(description="命令行待办事项管理")
subparsers = parser.add_subparsers(dest="command")
# 添加任务
add_parser = subparsers.add_parser("add")
add_parser.add_argument("title", help="任务标题")
add_parser.add_argument("-d", "--description", help="任务描述")
add_parser.add_argument("--due-date", help="截止日期(YYYY-MM-DD)")
# 列出任务
list_parser = subparsers.add_parser("list")
list_parser.add_argument("--all", action="store_true", help="显示已完成任务")
args = parser.parse_args()
if args.command == "add":
due_date = datetime.strptime(args.due_date, "%Y-%m-%d") if args.due_date else None
task_manager.add_task(args.title, args.description, due_date)
print(f"已添加任务: {args.title}")
elif args.command == "list":
tasks = task_manager.list_tasks(not args.all)
for task in tasks:
status = "✓" if task.is_completed else " "
print(f"[{status}] {task.id}: {task.title}")
if __name__ == "__main__":
task_manager = TaskManager()
main()
4.2 交互式改进方案
对于更友好的交互体验,可以结合input和while循环:
python复制def interactive_mode():
while True:
print("\n1. 添加任务 2. 完成任务 3. 任务列表 4. 退出")
choice = input("请选择操作: ")
if choice == "1":
title = input("任务标题: ")
description = input("任务描述(可选): ") or None
due_date_str = input("截止日期(YYYY-MM-DD, 可选): ")
due_date = datetime.strptime(due_date_str, "%Y-%m-%d") if due_date_str else None
task_manager.add_task(title, description, due_date)
elif choice == "2":
task_id = int(input("完成任务ID: "))
if task_manager.complete_task(task_id):
print("任务已完成!")
5. 高级功能实现
5.1 数据统计与报表
python复制def generate_weekly_report():
"""生成周任务统计报告"""
from datetime import timedelta
end_date = datetime.now()
start_date = end_date - timedelta(days=7)
completed = session.query(Task).filter(
Task.is_completed == True,
Task.created_at.between(start_date, end_date)
).count()
overdue = session.query(Task).filter(
Task.is_completed == False,
Task.due_date < end_date
).count()
print(f"\n本周工作统计:")
print(f"- 完成任务: {completed}个")
print(f"- 逾期任务: {overdue}个")
5.2 数据备份与恢复
python复制import shutil
from pathlib import Path
def backup_database():
"""备份SQLite数据库文件"""
db_file = Path("todo.db")
if db_file.exists():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = f"todo_backup_{timestamp}.db"
shutil.copy2(db_file, backup_file)
print(f"数据库已备份到 {backup_file}")
6. 生产环境部署建议
-
数据库选择:
- 个人使用:SQLite足够
- 团队协作:PostgreSQL+连接池
- 移动场景:考虑App内置SQLite+云同步
-
性能优化:
python复制engine = create_engine( "sqlite:///todo.db", connect_args={"check_same_thread": False}, pool_size=5, max_overflow=10 ) -
错误处理增强:
python复制from sqlalchemy.exc import SQLAlchemyError try: task = Task(title="重要任务") session.add(task) session.commit() except SQLAlchemyError as e: session.rollback() logger.error(f"数据库错误: {e}") raise
7. 项目扩展方向
- Web界面:用Flask/Django添加网页管理端
- 提醒功能:集成邮件/短信提醒
- 数据分析:使用Pandas生成可视化报表
- 多用户支持:添加用户认证系统
我在实际开发中发现,当任务量超过500条时,需要特别注意查询优化。一个实用的技巧是为常用查询字段添加索引:
python复制class Task(Base):
# ...
__table_args__ = (
Index('idx_task_due_date', 'due_date'),
Index('idx_task_completed', 'is_completed'),
)
这个命令行待办事项项目虽然简单,但涵盖了SQLAlchemy的核心用法。建议从基础功能开始,逐步添加自己需要的特性。我的开发经验是:先确保核心流程稳固,再考虑扩展功能,避免过度设计。