Flask入门实战:从零构建Python Web待办清单应用

发布时间:2026/7/30 14:40:43

Flask入门实战:从零构建Python Web待办清单应用
1. 项目概述为什么从Flask开始你的Web之旅如果你刚接触Python想快速做出一个能通过浏览器访问的玩意儿Flask几乎是你绕不开的起点。我刚开始学Web开发那会儿被各种复杂的概念和配置搞得晕头转向直到用了Flask才真正体会到“快速上手”是什么意思。它不像一些重型框架需要你先理解一大堆设计模式和目录结构才能写出“Hello World”。Flask的核心哲学是“微”它只提供最基础的工具剩下的怎么组织、用什么组件完全由你决定。这种自由度和极低的学习曲线让它成为个人项目、原型验证、API接口开发甚至是中小型应用后端的热门选择。今天我们就来手把手写一个简易的Web端程序。这个程序不仅仅是一个显示静态页面的玩具我会带你实现一个具备基础交互功能的小应用一个简易的待办事项清单。通过它你能理解Flask如何处理请求、渲染模板、连接数据库我们用轻量级的SQLite以及实现增删改查。整个过程我会穿插我踩过的坑和总结的技巧目标是让你看完就能自己搭起来并且知道每一步为什么这么做。文末会提供完整的、可运行的Demo代码。2. 环境准备与项目初始化2.1 搭建你的Python开发环境在写代码之前一个干净、独立的开发环境至关重要。这能避免不同项目间的包版本冲突。我强烈推荐使用venv来创建虚拟环境这是Python 3内置的工具无需额外安装。打开你的终端Windows上是CMD或PowerShellmacOS/Linux上是Terminal进入你打算存放项目的目录然后执行以下命令# 创建一个名为 flask_todo_demo 的项目文件夹并进入 mkdir flask_todo_demo cd flask_todo_demo # 创建虚拟环境环境文件夹命名为 venv python -m venv venv接下来激活虚拟环境Windows:venv\Scripts\activatemacOS/Linux:source venv/bin/activate激活后你的命令行提示符前通常会显示(venv)表示你已经在这个独立的环境中工作了。注意很多新手会忘记激活虚拟环境导致后续安装的包都装到了全局Python里造成混乱。每次打开新终端窗口进入项目时第一件事就是先激活虚拟环境。2.2 安装核心依赖包在激活的虚拟环境中我们使用pip安装必要的包。除了Flask本身我们还需要几个常用扩展pip install flask是的对于最基础的功能安装Flask本身就够了。但为了我们待办事项应用我们还需要Flask-SQLAlchemy: 一个强大的ORM对象关系映射工具让我们能用Python类来操作数据库而不用写复杂的SQL语句。Flask-WTF: 集成WTForms用于快速构建和验证Web表单防止跨站请求伪造CSRF攻击。让我们一次性安装它们pip install flask-sqlalchemy flask-wtf安装完成后可以通过pip list命令检查已安装的包及其版本。2.3 创建项目基础结构一个清晰的项目结构能让代码更易维护。在我们的项目根目录 (flask_todo_demo) 下创建如下文件和文件夹flask_todo_demo/ ├── app.py # 应用主入口文件 ├── config.py # 配置文件 ├── models.py # 数据库模型定义 ├── forms.py # 表单类定义 ├── routes.py # 路由和视图函数 ├── templates/ # HTML模板文件夹 │ └── index.html └── static/ # 静态资源文件夹CSS, JS, 图片你可以使用以下命令快速创建touch app.py config.py models.py forms.py routes.py mkdir templates static touch templates/index.html这个结构不是Flask强制要求的但遵循了常见的MVC模型-视图-控制器模式的思想将不同功能的代码分离开是良好的实践起点。3. 核心代码实现与原理拆解3.1 应用配置与初始化 (app.py, config.py)首先我们来配置应用。在config.py中我们设置一些关键配置# config.py import os class Config: # 密钥用于加密会话、CSRF保护等务必保密且随机 SECRET_KEY os.environ.get(SECRET_KEY) or you-will-never-guess-this-hard-string # 数据库URISQLite数据库文件将位于项目根目录下名为 app.db SQLALCHEMY_DATABASE_URI sqlite:///app.db # 追踪对象修改并发送信号会占用额外内存在不需要时可设为False SQLALCHEMY_TRACK_MODIFICATIONS False这里我选择将密钥放在环境变量中是更安全的生产环境做法。or后面的字符串是备用值仅用于开发。数据库使用了SQLite它是一个文件数据库无需安装服务器非常适合开发和演示。接下来在app.py中初始化Flask应用和扩展# app.py from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import Config # 初始化扩展但先不绑定应用 db SQLAlchemy() def create_app(config_classConfig): 应用工厂函数。这是一个最佳实践便于创建多个应用实例、进行测试等。 app Flask(__name__) # 加载配置 app.config.from_object(config_class) # 将扩展绑定到应用实例 db.init_app(app) # 在这里注册蓝图后续步骤 from routes import main_bp app.register_blueprint(main_bp) # 在应用上下文中创建数据库表 with app.app_context(): db.create_all() return app if __name__ __main__: app create_app() app.run(debugTrue) # debugTrue 开启调试模式代码修改后自动重启为什么使用工厂函数create_app直接app Flask(__name__)也能跑但工厂模式更灵活。它允许你基于不同配置如开发、测试、生产创建不同的应用实例也方便进行单元测试。db.init_app(app)这种延迟绑定模式是Flask扩展推荐的方式。3.2 定义数据模型 (models.py)模型对应数据库中的表。我们定义一个Todo模型来表示一条待办事项。# models.py from app import db from datetime import datetime class Todo(db.Model): 待办事项模型 id db.Column(db.Integer, primary_keyTrue) # 主键 title db.Column(db.String(100), nullableFalse) # 标题非空 description db.Column(db.Text) # 描述可为空 completed db.Column(db.Boolean, defaultFalse) # 完成状态默认为未完成 created_at db.Column(db.DateTime, defaultdatetime.utcnow) # 创建时间 def __repr__(self): return fTodo {self.title}db.Column定义了表的列。Integer,String,Boolean,DateTime是字段类型。primary_keyTrue表示这是主键唯一标识一条记录。nullableFalse表示该字段不能为空。default参数设置了字段的默认值。datetime.utcnow注意这里传递的是函数本身而不是函数调用结果这样每次创建记录时都会自动获取当前UTC时间。__repr__方法定义了对象的字符串表示在调试时非常有用。3.3 构建表单 (forms.py)我们使用Flask-WTF来创建表单它会自动处理CSRF令牌并提供方便的字段验证。# forms.py from flask_wtf import FlaskForm from wtforms import StringField, TextAreaField, BooleanField, SubmitField from wtforms.validators import DataRequired, Length class TodoForm(FlaskForm): 待办事项表单 title StringField(标题, validators[ DataRequired(message标题不能为空), Length(max100, message标题不能超过100个字符) ]) description TextAreaField(描述) completed BooleanField(已完成) submit SubmitField(提交)FlaskForm是所有表单的基类。StringField,TextAreaField等对应HTML中的input typetext,textarea。validators是验证器列表。DataRequired确保字段不为空Length限制长度。message参数可以自定义错误提示。表单在模板中渲染时会自动生成一个隐藏的CSRF令牌字段这是防范CSRF攻击的关键。3.4 实现路由与视图逻辑 (routes.py)路由决定了哪个URL由哪个函数来处理。视图函数则包含了处理请求和返回响应的核心逻辑。# routes.py from flask import Blueprint, render_template, request, redirect, url_for, flash from app import db from models import Todo from forms import TodoForm # 创建一个蓝图。蓝图是组织路由的模块化方式尤其适用于大型应用。 main_bp Blueprint(main, __name__) main_bp.route(/, methods[GET, POST]) def index(): 首页显示所有待办事项并处理新增表单 form TodoForm() if form.validate_on_submit(): # 如果是POST请求且表单验证通过 new_todo Todo( titleform.title.data, descriptionform.description.data, completedform.completed.data ) db.session.add(new_todo) db.session.commit() flash(待办事项已添加, success) # 发送成功消息 return redirect(url_for(main.index)) # 重定向到首页防止重复提交 # 获取所有待办事项按创建时间倒序排列 todos Todo.query.order_by(Todo.created_at.desc()).all() return render_template(index.html, formform, todostodos) main_bp.route(/complete/int:todo_id) def complete_todo(todo_id): 标记待办事项为完成/未完成 todo Todo.query.get_or_404(todo_id) # 找不到则返回404 todo.completed not todo.completed # 切换状态 db.session.commit() status 已完成 if todo.completed else 未完成 flash(f事项“{todo.title}”已标记为{status}, info) return redirect(url_for(main.index)) main_bp.route(/delete/int:todo_id) def delete_todo(todo_id): 删除待办事项 todo Todo.query.get_or_404(todo_id) db.session.delete(todo) db.session.commit() flash(f事项“{todo.title}”已删除, warning) return redirect(url_for(main.index))关键点解析Blueprint: 将路由组织在蓝图中使得应用结构更清晰。url_for(main.index)中的main就是蓝图的名字。validate_on_submit(): 这是一个非常方便的方法它同时检查请求方法是否为POST以及表单验证是否通过。db.session: SQLAlchemy使用会话Session来管理所有数据库操作。add()将对象加入会话commit()将会话中的改动提交到数据库。这是一个事务要么全部成功要么全部回滚。get_or_404(): 比get()更友好。如果根据ID找不到对象它会自动中止请求并返回一个404错误页面省去了我们手动判断的代码。flash(): 用于在下一次请求时向用户显示一次性消息。消息需要在模板中获取并显示。redirect(url_for(...)): 完成操作后重定向这是Post/Redirect/Get (PRG) 模式能有效避免用户刷新页面时重复提交表单。3.5 编写前端模板 (templates/index.html)Flask使用Jinja2模板引擎。模板允许我们混合HTML和动态内容。我们需要一个基础模板来保持页面结构一致但为了简化这里我们直接写一个完整的index.html。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title简易待办清单 (Flask Demo)/title link hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.1.3/dist/css/bootstrap.min.css relstylesheet style .completed { text-decoration: line-through; color: #6c757d; } .list-group-item { transition: all 0.2s; } /style /head body classbg-light div classcontainer mt-5 div classrow justify-content-center div classcol-md-8 h1 classmb-4 text-center 我的简易待办清单/h1 !-- 闪现消息 -- {% with messages get_flashed_messages(with_categoriestrue) %} {% if messages %} {% for category, message in messages %} div classalert alert-{{ category if category ! message else info }} alert-dismissible fade show rolealert {{ message }} button typebutton classbtn-close>python app.py你应该会看到类似下面的输出* Serving Flask app app * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 Press CTRLC to quit * Restarting with stat * Debugger is active! * Debugger PIN: 123-456-789打开浏览器访问http://127.0.0.1:5000你就能看到完整的待办事项应用了。尝试添加、完成、删除一些事项体验完整的交互流程。4.2 开发服务器与生产环境的区别请注意Flask输出的警告这是一个开发服务器不要用于生产环境。开发服务器如Werkzeug性能较弱且默认不支持并发仅用于开发和测试。对于生产环境你需要使用专业的WSGI服务器例如Gunicorn(Unix/Linux):pip install gunicorn然后使用gunicorn -w 4 app:create_app()启动。Waitress(Windows/Linux):pip install waitress然后在代码中通过waitress.serve(app, host0.0.0.0, port8080)启动。或者搭配NginxuWSGI等更复杂的部署方案。4.3 使用Flask调试器当debugTrue时如果代码出错浏览器中会显示一个交互式调试器。这是一个极其强大的开发工具但也存在安全风险。它允许你在错误页面上执行任意Python代码。因此绝对不要在生产环境中开启调试模式。在调试器页面上你可以查看完整的错误栈、局部变量值甚至可以在每个栈帧的上下文里执行命令这对于定位复杂Bug非常有用。5. 常见问题与进阶技巧5.1 数据库迁移当模型需要改变时我们当前在app.py中使用db.create_all()创建表。但这个方法有一个大问题它不会修改已有的表结构。如果你后来给Todo模型添加了一个新字段due_datedb.create_all()不会在已有的todo表中添加这个列。解决方案是使用Flask-Migrate扩展。它基于Alembic可以跟踪模型变化并生成迁移脚本。pip install flask-migrate修改app.py# app.py (部分修改) from flask_migrate import Migrate def create_app(config_classConfig): app Flask(__name__) app.config.from_object(config_class) db.init_app(app) migrate Migrate(app, db) # 初始化Migrate # ... 其余代码不变 ... # 移除 with app.app_context(): db.create_all() 这行然后使用命令行工具初始化迁移仓库、生成并应用迁移flask db init # 初始化只需一次 flask db migrate -m Initial migration. # 检测模型变化生成迁移脚本 flask db upgrade # 应用迁移更新数据库以后每次修改模型后重复migrate和upgrade命令即可。5.2 处理静态文件我们的static/文件夹用于存放CSS、JavaScript和图片。在模板中应该使用url_for(static, filenamestyle.css)来引用它们而不是硬编码路径/static/style.css。url_for能确保即使应用部署在子路径下如http://example.com/myapp/链接也能正确生成。5.3 表单验证与用户体验我们已经在后端通过WTForms做了验证。但为了更好的用户体验前端也应该有验证。HTML5提供了基本的验证属性我们可以让Jinja2渲染出来在表单字段定义中添加render_kw# forms.py (修改示例) title StringField(标题, validators[...], render_kw{required: True, maxlength: 100})这样渲染出的input标签会带有required和maxlength100属性浏览器会进行初步验证。但请记住前端验证可以被绕过后端验证永远是必须且最终的防线。5.4 项目结构扩展随着功能增多你可以将项目扩展成更标准的包结构flask_todo_demo/ ├── run.py # 启动脚本内容from app import create_app; app create_app() ├── config.py ├── app/ │ ├── __init__.py # 包初始化包含create_app工厂函数 │ ├── models.py │ ├── forms.py │ ├── routes/ │ │ ├── __init__.py │ │ └── main.py # 主路由蓝图 │ ├── templates/ │ └── static/ └── migrations/ # Flask-Migrate生成的文件夹这种结构更清晰适合中型项目。5.5 遇到的典型问题与排查ImportError: No module named flask或类似错误原因虚拟环境未激活或不在项目目录下安装。解决确认命令行提示符前有(venv)并确保在项目根目录下操作。sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: todo原因数据库表没有创建。解决检查app.py中db.create_all()是否在应用上下文中被调用。或者如果你使用了Flask-Migrate确保执行了flask db upgrade。修改了模板或代码但浏览器刷新没变化原因浏览器缓存或者Flask开发服务器未检测到更改某些编辑器保存方式特殊。解决硬刷新浏览器CtrlF5或CmdShiftR。如果还不行尝试重启Flask服务器。表单提交后数据没保存也没错误提示原因最常见的是表单没有通过验证但页面没有显示错误信息。排查检查模板中是否渲染了form.hidden_tag()包含CSRF令牌。检查是否在模板中遍历并显示了form.field.errors。在视图函数中可以在form.validate_on_submit()为False时打印form.errors来查看具体错误。Method Not Allowed错误原因视图函数只允许GET方法但你用POST请求访问了它或者反之。解决检查路由装饰器app.route(/path, methods[GET, POST])中是否包含了正确的请求方法。这个简易的Flask Web程序Demo麻雀虽小五脏俱全。它涵盖了路由、模板、表单、数据库ORM、闪现消息等核心概念。从这个小项目出发你可以轻松地扩展出用户登录、分页、API接口、文件上传等更多功能。最重要的是你理解了每个部分是如何连接和工作的而不仅仅是复制代码。

相关新闻

性价比高的贴牌铰链定制铰链自动化厂家

性价比高的贴牌铰链定制铰链自动化厂家

2026/7/30 14:40:43

在五金制造行业,铰链作为一种基础且关键的零部件,广泛应用于家具、橱柜、门窗等领域。对于众多企业客户而言,寻求性价比高的贴牌铰链定制服务以及自动化程度高的厂家,是降低成本、提升产品质量、增强市场竞争力的关键。然而&#…

树莓派运行Windows 11:ARM架构部署与性能实测指南

树莓派运行Windows 11:ARM架构部署与性能实测指南

2026/7/30 14:40:43

这次我们来看一个技术圈里很有意思的尝试:在树莓派上运行 Windows 11 系统。很多人可能觉得这是天方夜谭,毕竟树莓派是基于 ARM 架构的开发板,而 Windows 11 主要面向 x86 平台。但这个项目确实存在,而且有实际的性能测试数据。 …

织梦/帝国CMS内容自动化更新方案:告别手动发文的高效实操指南

织梦/帝国CMS内容自动化更新方案:告别手动发文的高效实操指南

2026/7/30 14:40:43

做网站运维、搭建站点的朋友,基本都用过织梦(DedeCMS)和帝国CMS。这两套老牌CMS虽然年头不短了,但胜在轻量化、改代码方便、兼容性够强,现在很多企业站、资讯站和个人博客依旧在用,受众非常广。但日常用下来…

涉外出生公证在哪里办理?涉外出生公证线上怎么办理?

涉外出生公证在哪里办理?涉外出生公证线上怎么办理?

2026/7/30 15:30:46

不少准备留学、移民、办理海外签证的朋友,都会被涉外出生公证难住。很多人不清楚涉外出生公证在哪里办理,身处异地不方便回老家,又好奇涉外出生公证线上怎么办理;有人来回奔波线下公证处,材料准备出错反复补件&#xf…

如何用嘎嘎降AI处理管理学论文:管理学毕业论文降AI免费4.8元知网达标完整教程

如何用嘎嘎降AI处理管理学论文:管理学毕业论文降AI免费4.8元知网达标完整教程

2026/7/30 15:30:46

如何用嘎嘎降AI处理管理学论文:管理学毕业论文降AI免费4.8元知网达标完整教程 关于管理学论文降AI教程,有几个细节提前知道能少走很多弯路。 核心用嘎嘎降AI(www.aigcleaner.com),4.8元,达标率99.26%。这…

构建跨平台PDF处理解决方案的5个架构设计最佳实践

构建跨平台PDF处理解决方案的5个架构设计最佳实践

2026/7/30 15:30:46

构建跨平台PDF处理解决方案的5个架构设计最佳实践 【免费下载链接】pdf-lib Create and modify PDF documents in any JavaScript environment 项目地址: https://gitcode.com/gh_mirrors/pd/pdf-lib PDF-Lib作为一款在任意JavaScript环境中创建和修改PDF文档的现代化库…

强化学习值迭代与策略迭代算法对比与实践

强化学习值迭代与策略迭代算法对比与实践

2026/7/30 15:30:46

1. 强化学习中的两种经典算法解析在强化学习领域,值迭代(Value Iteration)和策略迭代(Policy Iteration)是解决马尔可夫决策过程(MDP)问题的两大基础算法。这两种方法都基于动态规划思想,但在实现方式和计算效率上各有特点。作为一名长期从事智能算法开发…

告别系统卡顿:为何这款纯净装机工具成了技术小白的救星

告别系统卡顿:为何这款纯净装机工具成了技术小白的救星

2026/7/30 15:30:46

对于绝大多数Windows用户而言,“重装系统”四个字往往意味着麻烦的开始。无论是用了多年的旧电脑越变越慢,还是遭遇了难以清除的流氓软件,重装系统虽然是终极解决方案,但复杂的BIOS设置、晦涩的分区操作以及令人头疼的驱动安装&am…

Spring循环依赖原理深度解析:三级缓存机制与实战避坑指南

Spring循环依赖原理深度解析:三级缓存机制与实战避坑指南

2026/7/30 15:20:46

1. 从一个经典的面试题说起 “Spring是如何解决循环依赖的?” 这几乎是每一位Java后端开发者在面试Spring框架时都无法绕开的问题。我第一次被问到这个问题时,脑子里瞬间闪过的是“三级缓存”,然后试图把网上看来的标准答案复述一遍。但当我真…

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

[具身智能-649]:个人电脑搭建 RTSP 服务完整方案(Windows / Ubuntu 双平台,适配 RDK X5 rtsp2display 调试)

2026/7/30 9:53:22

目标:电脑作为RTSP 服务端,循环推送 H264/H265 视频流; RDK X5 通过 rtsp2display 拉流预览,完全不需要在开发板编译 live555。 提供两套成熟方案: ✅ 方案 A:FFmpeg(最简单,优先推…

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

2026/7/30 1:17:46

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

PDF拆分压完图糊了?2026国内免费实测,档案员都在用的组合方案

2026/7/30 2:52:37

说实话,提到PDF拆分再压缩,我真是被折腾得够呛。 上个月公司年度合同归档,一份300多页的PDF总合同,需要按年份拆分成三个独立文件,再分别压缩到10MB以内方便邮件发送各部门确认。我心想这还不简单?先找个海…

粉笔直播课适合周末集中备考考生突破吗

粉笔直播课适合周末集中备考考生突破吗

2026/7/30 0:09:54

本文面向在职备考、工作日难以抽出整块时间、只能依靠周末集中复习的公考考生,围绕"该平台直播课是否适配周末集中备考节奏、能否支撑瓶颈突破"这一核心问题做客观拆解。文中数据来源于公开财报、官网公示价格、第三方投诉平台公开投诉及用户社区讨论&…

ThreadLocal(存取变量)实战获取当前登录的员工

ThreadLocal(存取变量)实战获取当前登录的员工

2026/7/30 0:09:54

注意AOP所应用的注解以及service方法上自定义的Log注解

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案

2026/7/30 0:09:54

INAV飞控配置终极指南:从零到稳定飞行的完整解决方案 【免费下载链接】inav INAV: Navigation-enabled flight control software 项目地址: https://gitcode.com/gh_mirrors/in/inav INAV飞控配置是每个无人机爱好者必须掌握的核心技能,但很多新手…