十年前我刚接触Web开发时,搭建一个简单的待办事项系统需要整合五六个技术栈。如今基于Python的全栈方案让这件事变得优雅许多。这次我们要用Flask作为后端引擎,搭配Layui这个轻量级前端框架,构建一个功能完整且易于维护的待办事项管理系统。
选择Flask+Layui的组合主要基于三点考量:首先,Flask的微内核设计特别适合中小型Web应用快速迭代;其次,Layui提供的现成UI组件能大幅降低前端开发门槛;最后,这两个技术栈都有极低的学习曲线,特别适合全栈开发的入门实践。这个系统将包含用户认证、任务CRUD、状态管理等典型Web功能,完整覆盖从数据库设计到前端交互的全流程开发要点。
Flask框架采用典型的MVC模式,我们的项目结构会这样组织:
code复制/todoapp
/static # 存放Layui等静态资源
/templates # Jinja2模板文件
/models # SQLAlchemy数据模型
/views # 业务逻辑路由
config.py # 配置文件
app.py # 应用入口
数据库选用SQLite开发版+MySQL生产版的组合方案。SQLAlchemy作为ORM工具,其声明式语法可以这样定义任务模型:
python复制class Task(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
description = db.Column(db.Text)
status = db.Column(db.Integer, default=0) # 0待办 1进行中 2已完成
created_at = db.Column(db.DateTime, default=datetime.now)
Layui的模块化设计让我们可以按需加载组件。在base.html模板中需要引入这些核心模块:
html复制<link rel="stylesheet" href="/static/layui/css/layui.css">
<script src="/static/layui/layui.js"></script>
<!-- 按需加载模块 -->
<script>
layui.use(['layer', 'form', 'table'], function(){...});
</script>
特别说明选择Layui而非Vue/React的原因:对于这类管理型系统,我们更需要快速实现标准UI组件(如表单、表格)而非复杂交互。Layui的表格组件只需简单配置就能实现分页、排序等功能:
javascript复制layui.table.render({
elem: '#task-table',
url: '/api/tasks',
cols: [[
{field: 'title', title: '任务名称'},
{field: 'status', title: '状态', templet: '#statusTpl'}
]]
});
采用Flask-Login扩展实现认证流程。特别注意密码不能明文存储,这里使用Werkzeug的安全模块:
python复制from werkzeug.security import generate_password_hash, check_password_hash
class User(db.Model):
# ...其他字段
password_hash = db.Column(db.String(128))
@property
def password(self):
raise AttributeError('不可读取')
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
登录API的设计要兼顾RESTful和安全:
python复制@app.route('/api/login', methods=['POST'])
def login():
user = User.query.filter_by(username=request.json['username']).first()
if user and check_password_hash(user.password_hash, request.json['password']):
login_user(user)
return jsonify({'code': 0})
return jsonify({'code': 1, 'msg': '认证失败'}), 401
实现带JWT验证的任务API时,推荐使用Flask-HTTPAuth处理鉴权:
python复制from flask_httpauth import HTTPTokenAuth
auth = HTTPTokenAuth(scheme='Bearer')
@auth.verify_token
def verify_token(token):
g.user = User.verify_jwt(token)
return g.user is not None
@app.route('/api/tasks', methods=['GET'])
@auth.login_required
def get_tasks():
return jsonify([task.to_dict() for task in g.user.tasks])
前端调用时需在AJAX头部添加Token:
javascript复制layui.$.ajax({
url: '/api/tasks',
headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}
});
传统的轮询方式效率低下,我们改用Server-Sent Events实现状态推送:
python复制@app.route('/api/stream')
def stream():
def event_stream():
while True:
data = get_update()
yield f"data: {data}\n\n"
return Response(event_stream(), mimetype="text/event-stream")
前端通过EventSource监听变更:
javascript复制const source = new EventSource('/api/stream');
source.onmessage = function(e) {
layui.table.reload('task-table');
};
结合Python的csv模块和Flask的响应流,实现高效数据导出:
python复制@app.route('/api/export')
def export_csv():
def generate():
data = StringIO()
writer = csv.writer(data)
writer.writerow(['标题', '状态', '创建时间'])
yield data.getvalue()
for task in Task.query.all():
data.seek(0)
data.truncate(0)
writer.writerow([task.title, task.status, task.created_at])
yield data.getvalue()
headers = {'Content-Disposition': 'attachment; filename=tasks.csv'}
return Response(generate(), mimetype='text/csv', headers=headers)
使用Gunicorn+Nginx的经典部署方案时,需要注意这些配置要点:
bash复制# Gunicorn启动配置
gunicorn -w 4 -b 127.0.0.1:8000 app:app
# Nginx关键配置
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
当任务量超过10万条时,需要添加这些索引提升查询性能:
python复制class Task(db.Model):
# ...
__table_args__ = (
db.Index('idx_user_status', 'user_id', 'status'),
db.Index('idx_created', 'created_at')
)
对于状态变更频繁的场景,建议添加缓存层:
python复制from flask_caching import Cache
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
@app.route('/api/tasks')
@cache.cached(timeout=50, key_prefix='user_tasks_%s' % g.user.id)
def get_tasks():
return jsonify([task.to_dict() for task in g.user.tasks])
开发阶段经常遇到的CORS问题,可以通过Flask-CORS扩展解决:
python复制from flask_cors import CORS
CORS(app, resources={r"/api/*": {"origins": "*"}})
生产环境应该限制具体域名:
python复制CORS(app, resources={
r"/api/*": {
"origins": ["https://yourdomain.com"],
"methods": ["GET", "POST"],
"allow_headers": ["Authorization"]
}
})
利用Flask-WTF的CSRF保护机制:
python复制from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
# 在表单中添加令牌
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
</form>
对于AJAX请求,需要这样处理:
javascript复制layui.$.ajaxSetup({
headers: {
'X-CSRFToken': $('meta[name=csrf-token]').attr('content')
}
});
通过Celery实现异步定时提醒:
python复制from celery.schedules import crontab
app.conf.beat_schedule = {
'daily-reminder': {
'task': 'tasks.send_reminders',
'schedule': crontab(hour=9, minute=0)
},
}
@app.task
def send_reminders():
users = User.query.filter(User.settings['reminder'] == True).all()
for user in users:
send_email(user.email, '今日待办事项提醒')
利用Layui的响应式布局特性,在meta标签中添加viewport设置:
html复制<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
针对移动端优化表格显示:
javascript复制layui.table.render({
// ...
size: 'sm',
page: true,
limit: 10,
skin: 'line'
});
在项目开发过程中,我发现Flask的蓝图功能对大型项目特别有用,可以将不同模块拆分成独立的blueprint。比如把用户认证、任务管理分别放在/auth和/task两个蓝图中,这样既保持代码整洁又方便团队协作。另外推荐使用flask-migrate处理数据库变更,比直接执行SQL脚本更安全可靠。