作为一个长期与终端打交道的开发者,我始终认为命令行工具是最高效的生产力伙伴。今天要分享的,是一个用Python实现的命令行待办事项管理工具。这个工具完美融合了SQLAlchemy ORM的数据库操作能力和Python标准库的简洁性,特别适合习惯在终端工作的开发者。
这个工具的核心价值在于:
我曾尝试过各种任务管理工具,从复杂的项目管理软件到简单的文本文件,最终发现对于日常琐事管理,一个量身定制的命令行工具才是最趁手的解决方案。
在数据库访问层,我选择了SQLAlchemy ORM而非直接使用SQL语句,主要基于以下考虑:
对于小型工具而言,SQLite是最合适的数据库选择。它零配置、无服务器、单文件存储,完全符合我们的需求。SQLAlchemy对SQLite有原生支持,无需额外驱动。
整个应用采用经典的三层架构:
code复制命令行界面层(CLI)
↓
业务逻辑层
↓
数据访问层(SQLAlchemy)
↓
SQLite数据库
这种分层设计使得:
我们的待办事项应用需要跟踪以下信息:
对应的SQLAlchemy模型如下:
python复制from datetime import datetime
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Enum
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Task(Base):
__tablename__ = 'tasks'
id = Column(Integer, primary_key=True)
content = Column(String(200), nullable=False)
created_at = Column(DateTime, default=datetime.now)
due_date = Column(DateTime)
is_completed = Column(Boolean, default=False)
priority = Column(Enum('low', 'medium', 'high', name='priority_enum'))
category = Column(String(30))
def __repr__(self):
return f"<Task(id={self.id}, content='{self.content[:20]}...')>"
这个模型设计考虑了实际使用场景:
content限制200字符,避免过长描述created_at自动记录创建时间priority使用枚举类型确保取值规范__repr__方法方便调试我们使用SQLAlchemy的create_engine建立数据库连接,并配置自动创建表:
python复制from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# 使用SQLite内存数据库(开发环境)
# engine = create_engine('sqlite:///:memory:', echo=True)
# 使用文件数据库(生产环境)
engine = create_engine('sqlite:///todo.db')
Session = sessionmaker(bind=engine)
# 创建表(如果不存在)
Base.metadata.create_all(engine)
这里有几个实用技巧:
:memory:),测试更快速echo=True参数会打印所有SQL语句,方便调试python复制def add_task(session, content, due_date=None, priority='medium', category=None):
"""添加新任务到数据库"""
new_task = Task(
content=content,
due_date=due_date,
priority=priority,
category=category
)
session.add(new_task)
session.commit()
return new_task
使用示例:
python复制from datetime import datetime, timedelta
with Session() as session:
# 添加一个明天到期的高优先级任务
task = add_task(
session,
"完成项目文档",
due_date=datetime.now() + timedelta(days=1),
priority='high',
category='work'
)
实现一个灵活的查询方法,支持多种过滤条件:
python复制from sqlalchemy import or_
def get_tasks(session, completed=None, priority=None, category=None, search=None):
"""获取任务列表,支持多种过滤条件"""
query = session.query(Task)
if completed is not None:
query = query.filter(Task.is_completed == completed)
if priority:
query = query.filter(Task.priority == priority)
if category:
query = query.filter(Task.category == category)
if search:
query = query.filter(
or_(
Task.content.ilike(f"%{search}%"),
Task.category.ilike(f"%{search}%")
)
)
return query.order_by(Task.due_date).all()
这个方法展示了SQLAlchemy查询构建的强大之处:
ilike进行不区分大小写的模糊匹配or_组合多个匹配条件python复制def update_task_status(session, task_id, completed):
"""更新任务完成状态"""
task = session.query(Task).get(task_id)
if task:
task.is_completed = completed
session.commit()
return True
return False
python复制def delete_task(session, task_id):
"""删除指定任务"""
task = session.query(Task).get(task_id)
if task:
session.delete(task)
session.commit()
return True
return False
为了让工具更易用,我们使用Python标准库的argparse模块创建命令行界面:
python复制import argparse
from datetime import datetime
def parse_args():
"""解析命令行参数"""
parser = argparse.ArgumentParser(description='命令行待办事项管理工具')
subparsers = parser.add_subparsers(dest='command', required=True)
# 添加任务
add_parser = subparsers.add_parser('add', help='添加新任务')
add_parser.add_argument('content', help='任务内容')
add_parser.add_argument('-d', '--due-date', help='截止日期(YYYY-MM-DD)')
add_parser.add_argument('-p', '--priority', choices=['low', 'medium', 'high'],
default='medium', help='任务优先级')
add_parser.add_argument('-c', '--category', help='任务分类')
# 列出任务
list_parser = subparsers.add_parser('list', help='列出任务')
list_parser.add_argument('--completed', action='store_true', help='只显示已完成任务')
list_parser.add_argument('--pending', action='store_true', help='只显示未完成任务')
list_parser.add_argument('--priority', choices=['low', 'medium', 'high'], help='按优先级过滤')
list_parser.add_argument('--category', help='按分类过滤')
list_parser.add_argument('--search', help='搜索任务内容')
# 完成任务
done_parser = subparsers.add_parser('done', help='标记任务为已完成')
done_parser.add_argument('task_id', type=int, help='要完成的任务ID')
# 删除任务
delete_parser = subparsers.add_parser('delete', help='删除任务')
delete_parser.add_argument('task_id', type=int, help='要删除的任务ID')
return parser.parse_args()
为了让任务列表更易读,我们实现一个格式化输出的函数:
python复制def print_tasks(tasks):
"""美化打印任务列表"""
if not tasks:
print("没有找到任务")
return
print(f"{'ID':<5}{'状态':<8}{'优先级':<8}{'截止日期':<12}{'分类':<10} 内容")
print("-" * 60)
for task in tasks:
status = "✓" if task.is_completed else " "
priority = task.priority[0].upper() if task.priority else ""
due_date = task.due_date.strftime("%Y-%m-%d") if task.due_date else ""
category = task.category or ""
print(f"{task.id:<5}{status:<8}{priority:<8}{due_date:<12}{category:<10} {task.content[:50]}")
将数据库操作和命令行界面结合起来:
python复制def main():
args = parse_args()
session = Session()
try:
if args.command == 'add':
due_date = datetime.strptime(args.due_date, "%Y-%m-%d") if args.due_date else None
task = add_task(
session,
args.content,
due_date=due_date,
priority=args.priority,
category=args.category
)
print(f"已添加任务: {task.content}")
elif args.command == 'list':
completed = None
if args.completed:
completed = True
elif args.pending:
completed = False
tasks = get_tasks(
session,
completed=completed,
priority=args.priority,
category=args.category,
search=args.search
)
print_tasks(tasks)
elif args.command == 'done':
if update_task_status(session, args.task_id, True):
print(f"任务 {args.task_id} 标记为已完成")
else:
print(f"未找到任务 {args.task_id}")
elif args.command == 'delete':
if delete_task(session, args.task_id):
print(f"已删除任务 {args.task_id}")
else:
print(f"未找到任务 {args.task_id}")
except Exception as e:
print(f"错误: {e}")
session.rollback()
finally:
session.close()
if __name__ == '__main__':
main()
bash复制# 添加任务
python todo.py add "购买 groceries" -d 2023-12-31 -p high -c shopping
# 列出所有任务
python todo.py list
# 列出工作分类的任务
python todo.py list --category work
# 标记任务为已完成
python todo.py done 1
# 删除任务
python todo.py delete 2
bash复制# 搜索包含"报告"的任务
python todo.py list --search 报告
# 列出所有高优先级未完成的任务
python todo.py list --pending --priority high
# 列出今天到期的任务(结合shell命令)
python todo.py list | grep $(date +%Y-%m-%d)
会话管理最佳实践:
性能优化:
session.bulk_save_objects()yield_per()分批获取结果数据备份:
.dump命令导出数据错误处理增强:
扩展建议:
为了让工具更方便地在不同机器上使用,我们可以将其打包为Python包:
code复制todo-cli/
├── todo/
│ ├── __init__.py
│ ├── cli.py
│ ├── models.py
│ └── db.py
├── setup.py
└── README.md
python复制from setuptools import setup, find_packages
setup(
name='todo-cli',
version='0.1',
packages=find_packages(),
install_requires=[
'sqlalchemy>=1.4',
],
entry_points={
'console_scripts': [
'todo=todo.cli:main',
],
},
)
bash复制pip install -e .
安装后,可以直接使用todo命令调用工具,而不需要输入python脚本路径。
为了保证代码质量,我们应该为关键功能编写测试:
python复制import pytest
from datetime import datetime, timedelta
from todo.models import Task
from todo.db import Session, Base, engine
@pytest.fixture
def db_session():
# 使用内存数据库进行测试
test_engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(test_engine)
Session = sessionmaker(bind=test_engine)
session = Session()
# 添加测试数据
session.add_all([
Task(content="测试任务1", is_completed=False),
Task(content="测试任务2", is_completed=True),
])
session.commit()
yield session
session.close()
def test_add_task(db_session):
from todo.cli import add_task
task = add_task(db_session, "新测试任务")
assert task.id is not None
assert db_session.query(Task).count() == 3
def test_complete_task(db_session):
from todo.cli import update_task_status
result = update_task_status(db_session, 1, True)
assert result is True
assert db_session.query(Task).get(1).is_completed is True
这些测试覆盖了核心功能,可以在开发过程中快速反馈问题。建议使用pytest运行测试:
bash复制pytest -v
python复制class Task(Base):
# ...
category = Column(String(30), index=True)
priority = Column(Enum('low', 'medium', 'high', name='priority_enum'), index=True)
python复制engine = create_engine('sqlite:///todo.db', pool_size=5, max_overflow=10)
python复制# 批量插入示例
session.bulk_save_objects([
Task(content=f"任务{i}") for i in range(1000)
])
session.commit()
任务提醒:
数据统计:
多用户支持:
云同步:
自然语言处理:
这个命令行待办事项工具虽然简单,但包含了数据库应用的核心要素。通过SQLAlchemy ORM,我们实现了清晰的数据模型定义和高效的数据操作。结合Python强大的标准库,可以快速构建出实用的小工具。