Python Flask 零基础入门:从零搭建一个带 sqlite3 的 Web 应用
简介:这是一份面向Python Web开发初学者的Flask入门实践项目,以“试验楼小Demo”的形式呈现一个简易博文系统,涵盖用户登录登出、博文发布与查看等核心功能,适合刚接触Flask、希望从零跑通一个完整Web应用流程的读者练手。压缩包共8个文件,约5KB,包含1个py主程序、1个pyc编译文件、3个html模板、1个css样式表,以及1个sql建表脚本和1个db数据库文件,结构精简,便于对照理解路由、模板渲染与数据存储的配合关系。资源已有3088人学习下载,说明其作为入门样例具有一定参考价值。项目虽小,却串联起Flask框架基础、SQLite3数据存储、session身份验证、Jinja2模板渲染与表单处理等知识点,读者可据此了解用户表与博文表的设计思路、视图函数与URL映射方式,并在此基础上自行扩展错误处理、日志记录与部署运行等环节,是理解Web开发基本流程的一份轻量实践素材。
1. 先别急着写代码:Python Flask 到底是个什么东西
很多人第一次听到「Python Flask 开发实例」这几个字,脑子里冒出来的画面是:一堆看不懂的配置文件、黑乎乎的终端、还有网上那些动不动几千行的项目源码。于是还没开始就先把页面关了。我第一次接触 Flask 的时候也是这样,看到app = Flask(__name__)这行代码,心想这括号里下划线是干嘛的,是不是写错了。
其实你可以把 Flask 想成一个「极简的餐厅前台」。你写几行 Python,告诉它「有人访问首页,你就给他返回这句话」,它就老老实实照做。它不像某些大框架那样一上来就给你塞一整套规矩,而是先给你一个空盘子,你想加什么菜自己加。这就是为什么很多零基础的人学 Python web 开发,第一站会选 Flask——它足够小,小到你今天下午就能让一个网页在自己电脑上跑起来。
这份「自己敲的试验楼小 Demo」就是干这个的:用 Python 加 Flask,再配一个 sqlite3 小数据库,把「网页能显示内容、能存点数据」这条最基础的链路走通。它适合完全没碰过 web 开发、但会一点点 Python 的人。你不需要先学什么高深架构,跟着敲一遍,就能明白一个网站最朴素的骨架长什么样。
2. 为什么值得从这个小 Demo 入手:先跑通,再谈别的
2.1 零基础最怕的不是难,是「看不到结果」
学编程最容易放弃的时刻,不是遇到复杂算法,而是敲了半天代码,屏幕上什么都没发生。Flask 的好处是反馈特别快:你写一个路由,刷新浏览器就能看到字;你往 sqlite3 里插一条数据,页面上就能列出来。这种「我改一行、它变一下」的循环,对新手特别友好。
我见过不少 A 同学,一开始就去啃大型框架的官方文档,看了三天还在配置环境,最后不了了之。而这个 Demo 的路径是反过来的:先让一个最小页面跑起来,再慢慢往上加功能。你会在过程中自然遇到「为什么这里要写@app.route」「sqlite3 的?占位符是干嘛的」这些问题,带着问题去查,比干看文档记得牢得多。
2.2 Flask + sqlite3 这套组合,刚好够你理解「网站是怎么存东西的」
一个网站最核心的两件事:一是把页面发给用户看,二是把用户的数据存下来。Flask 负责第一件,sqlite3 负责第二件。sqlite3 是 Python 自带的数据库模块,不用你额外装数据库服务,一个文件就是一个库,删了文件库就没了,特别适合试验楼阶段。
你在这个 Demo 里会看到类似这样的代码:
import sqlite3 # 连接数据库,如果 demo.db 不存在会自动创建 conn = sqlite3.connect("demo.db") cursor = conn.cursor() # 建一张最简单的表,存留言 cursor.execute(""" CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL ) """) conn.commit() conn.close()这段代码的意思是:打开(或新建)一个叫demo.db的文件,在里面建一张叫messages的表,表里有两个字段,id是自动递增的编号,content是留言内容。IF NOT EXISTS是防止你重复运行时报表已存在的错。commit()是真正把改动写进文件,不写这句,前面白干——这是新手第一个血泪坑,后面会细说。
2.3 它帮你建立「请求—处理—响应」的直觉
你在浏览器地址栏敲一个网址,回车,页面出来。这中间发生了什么?Flask 的代码把这件事拆得很直白:
from flask import Flask, request, render_template_string app = Flask(__name__) @app.route("/") def index(): # 这里返回什么,浏览器就显示什么 return "试验楼首页,跑起来了" @app.route("/hello/<name>") def hello(name): # 地址里的 name 会被当成参数传进来 return f"你好,{name}"@app.route("/")的意思是「当有人访问根路径时,执行下面这个函数」。函数返回的字符串,就是浏览器看到的内容。第二段/hello/<name>演示了怎么从网址里取参数——你访问/hello/小明,页面就显示「你好,小明」。这种「地址对应函数、函数返回内容」的对应关系,就是 web 开发最底层的直觉,后面学再大的框架也是这个理。
3. 动手前的准备:环境搭好,心里不慌
3.1 确认你的 Python 和 pip 能用
这个 Demo 只需要 Python 3 和 Flask 库。先打开终端(Windows 叫命令提示符或 PowerShell),敲:
python --version pip --version能看到版本号就说明基础环境有了。如果提示找不到命令,去 Python 官网下载安装包时记得勾选「Add Python to PATH」,装完重开终端再试。这一步看着无聊,但它是后面所有操作的地基,地基不稳,后面全是玄学报错。
3.2 装 Flask,一条命令的事
pip install flask装完可以再敲pip show flask确认一下。这里有个小提醒:如果你电脑上同时有多个 Python 版本,可能装到了另一个版本里,运行时却用了这个版本,表现就是「明明装了却提示找不到 flask」。遇到这种情况,把pip换成python -m pip再装一次,基本能解决。
3.3 建一个干净的文件夹
新手容易把代码随手丢在桌面,文件越堆越乱。建议新建一个文件夹,比如叫flask_demo,后面所有文件都放里面。这不是形式主义,而是让你养成「一个项目一个窝」的习惯,以后文件多了不至于找不到。
4. 第一个能跑的 Flask 页面:从空白到浏览器出字
4.1 写一个最小的 app.py
在flask_demo文件夹里新建app.py,内容如下:
from flask import Flask # 创建 Flask 应用实例,__name__ 告诉它当前模块的位置 app = Flask(__name__) @app.route("/") def home(): return "<h1>我的试验楼开张了</h1>" # 只有直接运行这个文件时才启动,被 import 时不启动 if __name__ == "__main__": app.run(debug=True)逐行说:第一行把 Flask 类拿进来;app = Flask(__name__)是创建一个应用对象,括号里的__name__是 Python 自带的变量,表示当前文件的名字,Flask 靠它找模板和静态文件的位置;@app.route("/")把根路径绑到home函数;app.run(debug=True)启动内置服务器,debug=True的意思是改完代码自动重启,并且出错时页面会显示详细错误信息——新手一定要开,不然报错了你只能看到一句干巴巴的 500。
4.2 跑起来,看浏览器出字
在终端里进入flask_demo文件夹,执行:
python app.py你会看到类似Running on http://127.0.0.1:5000的输出。打开浏览器,地址栏输入127.0.0.1:5000,回车,页面上出现「我的试验楼开张了」。到这一步,你已经完成了一个 web 应用从零到可见的全过程。别小看这一行字,它证明你的 Python、Flask、端口、路由全都通了。
4.3 改一行,感受「热更新」
把home函数里的文字改成别的,保存,回到浏览器刷新。因为开了debug=True,你不用重启终端,刷新就能看到新内容。这个体验很重要:它让你敢于乱改,改坏了看报错,改对了看效果,学习就是在这一来一回里发生的。
5. 把 sqlite3 接进来:让页面能存能取
5.1 先单独把数据库跑通
别急着和 Flask 混在一起。新建一个init_db.py,先把建表和插数据跑通:
import sqlite3 conn = sqlite3.connect("demo.db") cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL ) """) # 插入一条测试数据,? 是占位符,防止拼接字符串出问题 cursor.execute("INSERT INTO messages (content) VALUES (?)", ("第一条留言",)) conn.commit() conn.close() print("数据库初始化完成")运行python init_db.py,文件夹里会多出一个demo.db。这里的?占位符是重点:不要用字符串拼接把用户输入直接塞进 SQL,那样既有注入风险,遇到引号也容易翻车。用?加元组传参,sqlite3 会帮你处理好转义。
5.2 在 Flask 里读数据并显示
回到app.py,加一个读取留言的页面:
import sqlite3 from flask import Flask app = Flask(__name__) def get_messages(): conn = sqlite3.connect("demo.db") cursor = conn.cursor() cursor.execute("SELECT id, content FROM messages ORDER BY id DESC") rows = cursor.fetchall() conn.close() return rows @app.route("/messages") def messages(): rows = get_messages() # 简单拼一个列表页,先不引入模板 html = "<h1>留言列表</h1><ul>" for row in rows: html += f"<li>{row[0]} - {row[1]}</li>" html += "</ul>" return htmlget_messages负责连库、查询、关连接,返回一个列表,每个元素是一行记录。messages路由拿到数据后拼成 HTML。访问127.0.0.1:5000/messages,你应该能看到刚才插入的那条留言。注意每次查询后都conn.close(),连接不关,文件被占用,后面写操作可能报「database is locked」,这是 sqlite3 最常见的坑之一。
5.3 再加一个提交表单,形成闭环
光能看还不够,得能写。加一个简单的表单页和提交处理:
from flask import request @app.route("/add", methods=["GET", "POST"]) def add(): if request.method == "POST": content = request.form.get("content", "").strip() if content: conn = sqlite3.connect("demo.db") cursor = conn.cursor() cursor.execute("INSERT INTO messages (content) VALUES (?)", (content,)) conn.commit() conn.close() return "提交成功,<a href='/messages'>去看列表</a>" return """ <form method="post"> <input name="content" placeholder="写点什么"> <button type="submit">提交</button> </form> """methods=["GET", "POST"]表示这个路由同时接受两种请求:直接访问是 GET,显示表单;点提交是 POST,走写入逻辑。request.form.get("content")取表单里 name 为 content 的值,.strip()去掉首尾空格,空内容不写库。到这里,你已经有了一条完整链路:表单提交 → 写进 sqlite3 → 列表页读出来。这就是一个最小可用的 web 应用。
6. 新手最容易踩的五个坑:现象、原因、解决
6.1 改了代码没反应
现象:保存了文件,刷新浏览器还是旧内容。原因:多半是没开debug=True,或者终端里跑的是旧进程。解决:确认app.run(debug=True),如果还不行,终端 Ctrl+C 停掉重新python app.py。有时候是浏览器缓存,强制刷新一次。
6.2 提示 database is locked
现象:提交表单时报 sqlite3 数据库被锁。原因:前面的连接没关,或者同时开了多个进程写同一个库。解决:检查每个connect后面是否都有对应的close,尤其是异常分支里也要关。入门阶段别开多线程写库,一个请求一个连接,用完就关。
6.3 表单提交后 405 Method Not Allowed
现象:点提交按钮,页面报方法不允许。原因:路由只写了@app.route("/add"),默认只接受 GET,而表单是 POST。解决:改成@app.route("/add", methods=["GET", "POST"])。这个报错很常见,看到 405 先查 methods。
6.4 中文显示成乱码
现象:页面上的中文变成问号或方块。原因:返回的 HTML 没声明编码,或者编辑器保存的文件编码不对。解决:在返回的 HTML 里加<meta charset="utf-8">,同时确认编辑器保存为 UTF-8。Flask 默认按 UTF-8 处理,多数乱码是编辑器那边出的问题。
6.5 端口被占用
现象:启动时报 Address already in use。原因:5000 端口被别的程序占了,或者你上一个 Flask 进程没退干净。解决:换端口app.run(debug=True, port=5001),或者找到占用进程关掉。入门阶段直接换端口最省事。
7. 跑通之后下一步学什么:从试验楼到能住人的房子
第一个例子跑通,说明你已经跨过了「不敢动手」这道坎。接下来怎么走,我给你一条按顺序来的路径,不用全学,挑着来。
| 阶段 | 学什么 | 为什么现在学 |
|---|---|---|
| 第一步 | Jinja2 模板 | 现在你是用字符串拼 HTML,页面一复杂就乱。模板让你把 HTML 和 Python 分开写 |
| 第二步 | 表单处理与简单校验 | 现在只判断了空内容,真实场景要防重复提交、长度限制 |
| 第三步 | 项目结构拆分 | 把路由、数据库操作分到不同文件,别全堆在 app.py |
| 第四步 | 用 ORM 替代手写 SQL | 表一多,手写 SQL 容易错,ORM 能帮你少写不少重复代码 |
先说模板。你现在返回的是拼出来的字符串,加个样式都费劲。Jinja2 是 Flask 自带的模板引擎,你把 HTML 写到templates/messages.html里,用{{ }}插变量,用{% for %}循环,代码会清爽很多。我第一次把拼字符串改成模板的时候,最大的感受是「原来页面可以写得像页面」。
再说项目结构。入门 Demo 全塞一个文件没问题,但当你加到第五个页面,app.py会变成一锅粥。可以试着建routes.py放路由、db.py放数据库函数,app.py只负责组装。这个拆分不用一步到位,边加功能边挪,挪一次你就理解一次「为什么要分」。
最后提一个习惯,也是我踩坑踩出来的:每加一个新功能,先在纸上或注释里写清楚「这个页面要读哪张表、写哪张表、失败时给用户看什么」,再动手敲。我以前图快,直接开写,结果写到一半发现表结构不对,回头改 SQL、改路由、改页面,返工的时间比想清楚的时间多得多。从那以后我每次加功能都强制自己先写这三行注释,哪怕只是试验楼小 Demo 也不跳过。希望这个习惯也能帮到你,少走一点我走过的弯路。
本文还有配套的精品资源,点击获取