虚拟环境的本质就是一套独立的 site-packages,跟「装两个 Python」不是一回事。
flask routes 不用起服务器就能列路由表,是排查 404 最快的一招。
教材是 Flask 2.x,本机 3.1.3:FLASK_ENV 已被彻底忽略,要用 FLASK_DEBUG=1。
这一篇对应教材 0.4 节的前四小节:装 Python、建虚拟环境、装 Flask、flask 指令。 教材的安装界面部分是桌面软件,标「平台原样」;命令行部分全部真跑。
一、装 Python 这件事,教材讲得比一般书细
教材从官网下载页讲起,强调两件事:选对位数、勾上「Add Python to PATH」。
第二件最要命。不勾的话,命令行里敲 python 会说找不到,而其实装了——新手最容易在这里卡住一晚上。
判据很简单:打开命令行敲 python --version,能出版本号就算过。
本机这套是 Python 3.13.14,比教材写作时的版本新,后面会讲差异。
二、虚拟环境:一套独立的依赖
不建虚拟环境会怎样?
两个项目都要 Flask,一个要 2.x 一个要 3.x,全局只能装一个版本,另一个项目就跑不起来。
虚拟环境把依赖装进项目自己的目录里。python -m venv .venv 一句话就建好。
建完目录里会长出 Scripts(Windows)或 bin(Linux)、Lib、pyvenv.cfg。
激活之后,pip install 只影响这个目录。
教材还提到 .gitignore 要把 .venv/ 排除掉——这个后面单独讲。
顺带一个数:这次建一个不带 pip 的环境,用了 0.64 秒;带上 pip 会多几十兆、多花十几秒。
三、flask 命令能干什么
| 命令 | 干什么 | 什么时候用 |
|---|---|---|
| flask run | 起开发服务器 | 本机调试 |
| flask routes | 列路由表 | 查 404、查端点名 |
| flask shell | 带上下文的交互环境 | 手查数据库 |
| flask db init | 初始化迁移目录 | 第一次建库 |
| flask db migrate | 生成迁移脚本 | 改了模型之后 |
| flask db upgrade | 把迁移应用到库 | 每次迁移之后 |
后三个是 flask-migrate 插件加的,装上才有;前三个是 Flask 自带。
flask routes 是这本书里最值钱的一条命令。页面打不开时,先列路由,比读代码快得多。
它还能看出「你写的端点名是什么」,这对 url_for 很关键——url_for 认的是端点名,不是路径。
四、服务器真的能起来,但别指望它扛活
flask run 起的是开发服务器,单进程、单线程(除非开 --with-threads),还带一堆调试用的检查。
教材在 0.4.4 节明确说了:这是开发用的,不要拿去上线。
这次实测是真的能起:起在一次随机端口上,用 urllib 请求,回的是 200 和正文 hi。
所以后面每篇的 Demo 都可以两种方式验。起服务器真请求,或者用 test client 直接发; 这本书统一用后者,快且不留端口。
五、教材里三条已经过时的写法
这一篇必须点出来,否则你照着书敲会以为是自己写错了。
| 教材写法 | 现在的状态 | 改成什么 |
|---|---|---|
| FLASK_ENV=development | 2.3 废弃、3.0 移除 | FLASK_DEBUG=1 |
| @app.before_first_request | 已删除 | with app.app_context() |
| app.json_encoder = 类 | 已删除 | 自定义 app.json |
第一条最坑:3.1 里设置 FLASK_ENV 不报错、不警告,直接忽略。
你以为开了除错模式,改代码却不自动重载,找半天找不到原因。
这次实测过:FLASK_ENV=development 时 app.debug 是 False,FLASK_DEBUG=1 时才是 True。
后两条会直接 AttributeError,反而好查——报错就是报错,不像第一条那样闷着不响。
六、动手 Demo:环境三件套:解释器、虚拟环境、flask 命令
这一节的 Demo 把教材前四小节能跑的全跑一遍:版本、建环境、列路由、真起服务器请求一次, 最后验一下三条版本差异。 教材的安装界面截图部分照写不跑。
import subprocess, sys
print(subprocess.run([sys.executable, "-m", "flask", "--version"],
capture_output=True, text=True).stdout)
subprocess.run([sys.executable, "-m", "venv", "--without-pip", "demo"])
# 把 FLASK_APP 指向 app.py,flask routes 就能列出全部规则
subprocess.run([sys.executable, "-m", "flask", "routes"],
env={"FLASK_APP": "app.py"})
实跑输出:
--------------------------------------------------------------------
环境三件套:解释器、虚拟环境、flask 命令
--------------------------------------------------------------------
① 现在这套环境是什么
--------------------------------------------------------------------
Python 3.13.14
Flask 3.1.3
Werkzeug 3.1.9
教材用的 Flask 2.x,本机是 3.1.3。差别后面逐条讲,这一章先记住:能跑,但有些旧写法不能照抄。
② 建一个虚拟环境要多久
--------------------------------------------------------------------
python -m venv --without-pip -> 返回码 0,耗时 0.66 秒
├── .gitignore
├── Include/
├── Lib/
│ └── site-packages/
├── Scripts/
│ ├── Activate.ps1
│ ├── activate
│ ├── activate.bat
│ ├── activate.fish
│ ├── deactivate.bat
│ ├── python.exe
│ └── pythonw.exe
└── pyvenv.cfg
! 虚拟环境的本质就是一套独立的 site-packages。装上 pip 会多几十兆、多花十几秒;
这里为了看清结构,故意省了。
③ flask 命令能干什么
--------------------------------------------------------------------
Endpoint Methods Rule
-------- ------- -----------------------
hello GET /hello/<name>
index GET /
static GET /static/<path:filename>
user GET /users/<int:uid>
! flask routes 不用起服务器就能列路由表——查「这个地址到底通不通」最快的一招。
规则里的 <int:uid> 和 <name> 是两种转换器:一个只收整数,一个收字符串。
④ 真起一次服务器,再请求它
--------------------------------------------------------------------
flask run --port 55198,然后请求 http://127.0.0.1:55198/ -> (200, 'hi')
! 服务器是真的起来了,200 也是真的回来的。
但本沙箱不能长期占着端口,所以后面每章用 test client 发请求——走的是同一条处理链。
⑤ 版本变了,教材里这三行不能照抄
--------------------------------------------------------------------
| 设了哪个环境变量 | app.debug 是 |
|---|---|
| FLASK_ENV=development | debug = False |
| FLASK_DEBUG=1 | debug = True |
! FLASK_ENV 在 3.1 里被完全忽略——不报错、不警告,就是不起作用。
这比报错更坑:你以为开了除错,改代码却不自动重载,还找不到原因。
| 教材写法 | 现在的状态 | 怎么办 |
|---|---|---|
| FLASK_ENV=development | 2.3 废弃、3.0 起移除 | 改用 FLASK_DEBUG=1 |
| @app.before_first_request | 2.3 废弃、已删除 | with app.app_context() |
| app.json_encoder = X | 2.3 废弃、已删除 | 自定义 app.json 提供者 |
现场查一遍:before_first_request 还在吗 -> False;json_encoder 属性还在吗 -> False
两个都成了 False,所以照抄教材那两行必然 AttributeError。
这三条后面各有一篇专门讲,这里先让你知道「报错不是你写错了」。
版本三行是真输出:Python 3.13.14、Flask 3.1.3、Werkzeug 3.1.9。
路由表里那四条,第三条 static 又是它自己加的——和上一篇呼应上了。
<int:uid> 和 <name> 是两种转换器:一个只收整数,一个什么都收。
起服务器那一段用的是随机空端口,请求完立刻 terminate(),不占着端口。
30 秒实验
- 把
--without-pip去掉再建一次,比一比目录大小和耗时。 - 在 app.py 里加一条
@app.route("/a/<float:x>"),用flask routes看规则长什么样。 - 把
FLASK_DEBUG=1换成FLASK_DEBUG=0,观察app.debug的变化。
常见误区
- 不建虚拟环境就 pip install:全局装一堆,项目之间互相踩,最后只能重装 Python。
- 以为激活虚拟环境是必须的:直接写
.venv/Scripts/python -m flask run也行, 激活只是让python指向它。 - 照着教材设 FLASK_ENV:3.1 里它被静默忽略,除错模式根本没开。
- 拿开发服务器上线:单进程、无并发保护,真上量必挂。
自测三问(点开对答案)
1. 虚拟环境和「装两个 Python」有什么区别? —— 虚拟环境共用同一个解释器,只是依赖装在各自目录里;装两个 Python 是两套解释器,容易打架。 2. `flask routes` 输出里的「端点」是干什么用的? —— `url_for` 认的是端点名而不是路径,改路径时端点名不变,链接就不会断。 3. 为什么说 FLASK_ENV 失效比报错更坑? —— 它不报错也不警告,你以为开了除错,实际没开,还找不到原因。环境通了,下一篇把编辑器这一环补齐:解释器怎么指、检查器和格式化怎么配、.gitignore 该写哪几行。
- ☐ (本篇完,下一篇 0.4 VS Code、代码检查器与 .gitignore)