系列:Python Web 框架
Flask 是 Python Web 里很典型的“微框架”:核心很小,路由、请求、响应、模板这些基础东西给你,其他都让你自己选。
这既是优点,也是坑。写一个内部工具、回调接口、机器学习 demo,Flask 很顺手;但如果你上来就要用户系统、权限、后台、复杂数据库模型,Flask 不会像 Django 那样把路铺好。
如果你还没看过专题总览,可以先读 Python Web 框架有哪些,怎么选。这篇只讲怎么把 Flask 项目跑起来,并且用一个不会太假的目录结构收尾。
适用场景
Flask 适合这些情况:
- 你要快速写一个小 Web 页面或内部工具;
- API 不多,业务逻辑也不重;
- 你希望自己选择 ORM、配置方式、认证方案;
- 团队已经有 Flask 存量项目,需要继续维护。
不太适合这些情况:
- 一开始就知道会做成大型后台系统;
- 需要开箱即用的后台管理;
- API 文档、数据校验、类型提示是刚需;
- 团队新人多,希望框架强约束项目结构。
这也是它和 Django 安装与使用指南、FastAPI 安装与使用指南 最大的差别:Flask 给的是最小起点,不是完整方案。
创建项目
先建目录和虚拟环境:
mkdir flask-democd flask-demopython3 -m venv .venvsource .venv/bin/activate安装 Flask:
pip install flask确认版本:
python -m flask --version如果网络慢,可以先看 pip 源的设置和使用 配好镜像源。
第一个应用
创建 app.py:
from flask import Flask
app = Flask(__name__)
@app.get("/")def index(): return "Hello, Flask!"启动开发服务器:
flask --app app run --debug打开 http://127.0.0.1:5000/,能看到 Hello, Flask!。
--debug 会开启调试模式和自动重载,只适合开发环境。生产环境不要开。
路由和路径参数
Flask 的路由写法很直接:
@app.get("/users/<int:user_id>")def get_user(user_id: int): return {"id": user_id, "name": "Alice"}常见转换器:
<name> 字符串<int:id> 整数<float:num> 浮点数<path:file> 带斜杠的路径如果要支持多个 HTTP 方法:
@app.route("/users", methods=["GET", "POST"])def users(): return {"message": "ok"}小项目这么写没问题。路由一多,就不要全塞进 app.py,后面会拆 Blueprint。
请求参数和 JSON
查询参数用 request.args:
from flask import Flask, request
app = Flask(__name__)
@app.get("/search")def search(): keyword = request.args.get("q", "") page = request.args.get("page", 1, type=int) return {"q": keyword, "page": page}JSON 请求体用 request.get_json():
@app.post("/users")def create_user(): data = request.get_json() or {} name = data.get("name") if not name: return {"error": "name is required"}, 400 return {"name": name}, 201这里能看出 Flask 的特点:它不会自动帮你做数据模型校验。你可以手写,也可以接 Marshmallow、Pydantic 或 webargs。小项目手写能接受,大项目最好别靠 dict.get() 撑到底。
返回 HTML 模板
创建目录:
flask-demo/├── app.py└── templates/ └── index.htmltemplates/index.html:
<!doctype html><html lang="zh-CN"> <head> <meta charset="utf-8" /> <title>Flask Demo</title> </head> <body> <h1>{{ title }}</h1> <ul> {% for item in items %} <li>{{ item }}</li> {% endfor %} </ul> </body></html>app.py:
from flask import Flask, render_template
app = Flask(__name__)
@app.get("/")def index(): return render_template( "index.html", title="Flask Demo", items=["route", "template", "config"], )Flask 默认用 Jinja2 模板。变量会自动转义,正常输出用户输入时不要随手加 |safe。
配置和环境变量
最简单的配置方式:
import osfrom flask import Flask
app = Flask(__name__)app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", "dev-only")实际项目里,我更喜欢把配置集中放到一个类里:
import os
class Config: SECRET_KEY = os.environ.get("SECRET_KEY", "dev-only") DATABASE_URL = os.environ.get("DATABASE_URL", "sqlite:///app.db")然后在入口加载:
app = Flask(__name__)app.config.from_object("config.Config")注意:SECRET_KEY、数据库密码、第三方 token 不要写死到 Git 仓库里。Flask 项目看起来小,也一样会泄露密钥。
用 Blueprint 拆路由
项目稍微长一点,就建议拆:
flask-demo/├── app/│ ├── __init__.py│ └── routes.py├── config.py└── wsgi.pyapp/routes.py:
from flask import Blueprint
bp = Blueprint("main", __name__)
@bp.get("/")def index(): return {"message": "hello"}app/__init__.py:
from flask import Flask
def create_app(): app = Flask(__name__) app.config.from_object("config.Config")
from .routes import bp app.register_blueprint(bp)
return appwsgi.py:
from app import create_app
app = create_app()启动:
flask --app wsgi run --debug这种 create_app() 写法是 Flask 里很常见的应用工厂模式。它比全局 app = Flask(__name__) 更适合测试和多环境配置。
常见问题
flask 命令找不到
先确认虚拟环境已激活:
source .venv/bin/activatepython -m flask --version如果 flask 命令仍然不可用,可以直接用:
python -m flask --app app run --debug修改代码没有自动重载
确认启动时带了 --debug:
flask --app app run --debug不要在生产环境依赖这个模式。
返回中文乱码
现代 Flask 返回 JSON 通常不会有问题。如果你手动构造响应,确保 content type 带 charset:
from flask import Response
return Response("你好", content_type="text/plain; charset=utf-8")Flask 要不要用 async
Flask 支持 async def 视图,但它不是像 FastAPI 那样的原生 ASGI 异步框架。大多数 Flask 项目用同步写法就够了。如果你从一开始就要大量异步 I/O,直接选 FastAPI 安装与使用指南 更省心。
总结
Flask 的优势不是“功能强”,而是“起步轻”。它适合小工具、内部页面、轻量 API 和原型验证。
一个比较稳的 Flask 起步方式是:
先用 app.py 跑通功能路由多了拆 Blueprint配置集中到 config.py数据库、认证、表单校验按需引入生产部署交给 Gunicorn 或 uWSGI如果你要做完整后台系统,优先看 Django 安装与使用指南;如果你要做类型友好的 API,优先看 FastAPI 安装与使用指南。Flask 最适合的是中间那块:不想背完整框架,又不想从零写 HTTP 细节。更多细节可以参考 Flask 官方文档。