🧪 第0章 Flask 的概要与环境架设
📄 一句话概括

虚拟环境的本质就是一套独立的 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 秒实验

  1. 把 --without-pip 去掉再建一次,比一比目录大小和耗时。
  2. 在 app.py 里加一条 @app.route("/a/<float:x>"),用 flask routes 看规则长什么样。
  3. 把 FLASK_DEBUG=1 换成 FLASK_DEBUG=0,观察 app.debug 的变化。

常见误区

  1. 不建虚拟环境就 pip install:全局装一堆,项目之间互相踩,最后只能重装 Python。
  2. 以为激活虚拟环境是必须的:直接写 .venv/Scripts/python -m flask run 也行, 激活只是让 python 指向它。
  3. 照着教材设 FLASK_ENV:3.1 里它被静默忽略,除错模式根本没开。
  4. 拿开发服务器上线:单进程、无并发保护,真上量必挂。
自测三问(点开对答案) 1. 虚拟环境和「装两个 Python」有什么区别? —— 虚拟环境共用同一个解释器,只是依赖装在各自目录里;装两个 Python 是两套解释器,容易打架。 2. `flask routes` 输出里的「端点」是干什么用的? —— `url_for` 认的是端点名而不是路径,改路径时端点名不变,链接就不会断。 3. 为什么说 FLASK_ENV 失效比报错更坑? —— 它不报错也不警告,你以为开了除错,实际没开,还找不到原因。

环境通了,下一篇把编辑器这一环补齐:解释器怎么指、检查器和格式化怎么配、.gitignore 该写哪几行。

相关笔记