首页
/ Flask 项目布局:从单文件应用到 flaskr 博客包的完整目录结构设计

Flask 项目布局:从单文件应用到 flaskr 博客包的完整目录结构设计

2026-09-04 21:04:46作者:郦嵘贵Just

本文基于 Flask 官方教程的第一节“Project Layout”,讲清一个 Flask 项目应当如何组织目录:从最简单的单文件 hello.py 起步,逐步演进为包含应用包、测试目录、虚拟环境和打包安装的工程化结构,并结合 Flask 仓库中 examples/tutorial 下的完整参考实现,解释每个目录和文件在应用工厂、数据库初始化与测试体系中的实际作用。读完后你将能够独立搭建一个可扩展、可安装、可测试的 Flask 项目骨架。

1. 创建项目目录与最简应用

Flask 教程要求首先创建并进入一个项目目录(官方示例名为 flask-tutorial):

$ mkdir flask-tutorial
$ cd flask-tutorial

之后按照 安装指南 配置 Python 虚拟环境并安装 Flask。教程从这一步开始默认你工作在 flask-tutorial 目录下,后续代码块顶部的文件名都是相对该目录的路径。

一个 Flask 应用可以简单到只有一个文件。教程给出的最小示例 hello.py 如下:

# hello.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello, World!'

但正如教程所提醒的:随着项目变大,把所有代码塞进一个文件会变得难以维护。Python 项目使用*包(package)*把代码组织成多个可导入的模块,Flask 教程也正是这样做的。

2. 项目目录的构成

教程明确了项目目录应包含的内容:

  • flaskr/:一个 Python 包,存放你的应用代码和文件;
  • tests/:存放测试模块的目录;
  • .venv/:安装了 Flask 及其他依赖的 Python 虚拟环境;
  • 安装文件,告诉 Python 如何安装你的项目;
  • 版本控制配置(如 git)。教程建议无论项目大小,都养成使用某种版本控制的习惯;
  • 未来可能添加的其他项目文件。

教程给出的最终项目布局如下:

/home/user/Projects/flask-tutorial
├── flaskr/
│   ├── __init__.py
│   ├── db.py
│   ├── schema.sql
│   ├── auth.py
│   ├── blog.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── auth/
│   │   │   ├── login.html
│   │   │   └── register.html
│   │   └── blog/
│   │       ├── create.html
│   │       ├── index.html
│   │       └── update.html
│   └── static/
│       └── style.css
├── tests/
│   ├── conftest.py
│   ├── data.sql
│   ├── test_factory.py
│   ├── test_db.py
│   ├── test_auth.py
│   └── test_blog.py
├── .venv/
└── pyproject.toml

这个布局在 Flask 仓库中有一份可以直接对照的完整实现:examples/tutorial 目录就是教程项目的最终产物,其内部结构与上图完全一致(flaskr/ 包、tests/ 目录、pyproject.toml),可以在跟随教程时随时与自己的项目比对。

3. 用 .gitignore 忽略生成文件

如果使用版本控制,教程建议把运行项目时自动生成的文件加入忽略列表;对于编辑器产生的其他文件同理——总原则是:忽略那些不是你亲手写的文件。教程给出的 .gitignore 示例:

.venv/

*.pyc
__pycache__/

instance/

.pytest_cache/
.coverage
htmlcov/

其中 instance/ 这一项值得特别留意,它的来源正是应用工厂的实现。在 examples/tutorial/flaskr/init.py 中,create_app 创建应用时显式启用了实例目录并把数据库放到其中:

app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
    # a default secret that should be overridden by instance config
    SECRET_KEY="dev",
    # store the database in the instance folder
    DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
)

并且随后执行 os.makedirs(app.instance_path, exist_ok=True) 确保该目录存在。这意味着 instance/flaskr.sqlite 是运行时产物、可能包含用户数据,绝不能提交到版本库——这正是 .gitignore 中包含 instance/ 的原因。而 .venv/__pycache__/.pytest_cache/.coveragehtmlcov/ 则分别对应虚拟环境、Python 字节码缓存和测试覆盖率工具的运行残留。

4. flaskr 包内部结构:每个文件承担什么职责

对照仓库中的参考实现,可以逐个理解 flaskr/ 包内文件的职责分工。

4.1 __init__.py:应用工厂与模块装配

examples/tutorial/flaskr/init.py 定义了 create_app(test_config=None) 工厂函数,它把包内各模块串接起来:

  1. 创建 Flask 实例并写入默认配置(SECRET_KEYDATABASE 指向 instance 目录);
  2. 非测试环境下从 instance 目录静默加载 config.py,测试环境则用传入的 test_config 更新配置;
  3. 确保 instance 目录存在;
  4. 注册 db.init_app(app) 初始化数据库命令;
  5. 注册 authblog 两个 Blueprint,并通过 app.add_url_rule("/", endpoint="index")url_for("index") 直接指向博客首页。

这里体现了包结构的两个关键收益:测试可注入test_config 参数让每个测试拿到独立配置的应用实例)与延迟注册(各模块在工厂内部按需导入,避免循环依赖)。

4.2 db.pyschema.sql:数据库模块与初始化脚本

examples/tutorial/flaskr/db.py 提供三个核心函数:

  • get_db():按 current_app.config["DATABASE"] 建立 SQLite 连接,并缓存在 g 上,保证同一请求复用连接;
  • close_db():请求结束时关闭连接,通过 app.teardown_appcontext(close_db) 挂接(见 db.py L51-L56);
  • init_db():读取 schema.sql 并执行,重建数据表。

init_db 还封装成了 Click 命令 flask init-dbdb.py L41-L45),可以在 flask CLI 下执行。而 examples/tutorial/flaskr/schema.sql 定义了博客的两张表 userpost(含外键关联),SQL 文件独立于 Python 代码存放,便于单独修改表结构而不触碰 Python 逻辑。

4.3 auth.pyblog.py:以 Blueprint 划分功能

examples/tutorial/flaskr/auth.py 顶部声明了 bp = Blueprint("auth", __name__, url_prefix="/auth"),登录、注册、登出视图全部挂在该前缀下;examples/tutorial/flaskr/blog.py 则以 Blueprint("blog", __name__) 承载文章列表、新建、编辑、删除视图。这种“一个模块一个功能域 + 一个 Blueprint”的划分方式,就是模板目录分成 templates/auth/templates/blog/ 两个子目录的原因——模板组织与代码模块组织保持一一对应,视图渲染时 render_template("auth/login.html") 自然落在对应子目录中。

4.4 templates/static/:Flask 的资源约定

Flask 默认从应用包内查找 templates/(模板)和 static/(静态文件)两个目录。参考项目中 examples/tutorial/flaskr/templates/base.html 是所有页面的继承基模板,auth/ 子目录放 login.htmlregister.htmlblog/ 子目录放 create.htmlindex.htmlupdate.htmlstatic/style.css 则是全站唯一的样式文件,定义了正文最大宽度 960px、标题衬线字体等基础外观(见 style.css)。把资源放在应用包内部(而非项目根目录)的好处是:包被打包安装到别的机器后,模板和静态文件会随包一起分发。

5. tests/ 目录:测试与应用的对应关系

tests/ 目录中的每个 test_*.py 文件与包内模块一一对应:test_factory.py 测工厂函数,test_db.py 测数据库命令,test_auth.py 测认证,test_blog.py 测博客功能。共享的 pytest fixture 集中在 examples/tutorial/tests/conftest.py

  • app fixture 通过 create_app({"TESTING": True, "DATABASE": db_path}) 为每个测试创建独立临时数据库的独立应用实例,测试结束后删除临时文件;
  • client fixture 返回 app.test_client() 供视图请求测试使用;
  • auth fixture 封装了 login/logout 动作,避免各测试重复编写登录请求。

tests/data.sql 则是测试数据种子脚本——conftest.py 在初始化数据库后通过 get_db().executescript(_data_sql) 插入两个用户和若干文章(见 data.sql),供认证和博客测试引用固定数据。

6. pyproject.toml:让项目可安装的最后一块拼图

布局树中唯一的非目录文件 pyproject.toml 承担“告诉 Python 如何安装你的项目”的职责。参考实现 examples/tutorial/pyproject.toml 展示了教程项目的完整配置:

[project]
name = "flaskr"
version = "1.0.0"
description = "The basic blog app built in the Flask tutorial."
readme = "README.rst"
license = {file = "LICENSE.txt"}
maintainers = [{name = "Pallets", email = "contact@palletsprojects.com"}]
classifiers = ["Private :: Do Not Upload"]
dependencies = [
    "flask",
]

[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"

[tool.flit.module]
name = "flaskr"

[tool.flit.sdist]
include = [
    "tests/",
]

[tool.pytest.ini_options]
testpaths = ["tests"]
filterwarnings = ["error"]

几个要点值得说明:

  • dependencies = ["flask"] 声明运行时依赖,安装项目时 Flask 会一并安装;
  • [project.optional-dependencies] test = ["pytest"](见完整文件)将测试依赖设为可选项,用 pip install .[test] 才能装上 pytest;
  • build-system 指定 flit_core 作为打包后端,[tool.flit.module] name = "flaskr"flaskr/ 目录映射为可导入的模块;
  • [tool.flit.sdist] include = ["tests/"] 把测试目录打进源码分发,方便他人验证;
  • [tool.pytest.ini_options] testpaths = ["tests"]pytest 无需参数即可定位测试;filterwarnings = ["error"] 则把警告提升为错误,保证测试输出的严格性。

有了这份文件,pip install -e . 就能在可编辑模式下安装整个项目,flask --app flaskr run 也就能通过应用工厂启动开发服务器。

7. 小结与下一步

layout 一节的核心结论是:Flask 并不强制任何项目结构,但教程刻意采用“包 + 测试 + 虚拟环境 + 打包文件”的工程化骨架,用少量前期样板代码避开新手常见陷阱(单文件膨胀、配置与实例数据混淆、测试互相污染),换来一个易于扩展和部署的项目。

完成目录创建后,教程的下一步是编写 应用工厂 create_app()(Continue to factory);完整的成品代码可以持续对照仓库中的 examples/tutorial 目录,包括 auth.pyblog.pydb.py 及各 测试文件 的实现。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384