environment-setup:Python 虚拟环境管理、pip install flask 与首个规范 App

📂 所属阶段:第一阶段 — 破冰启航(基础篇)
🔗 相关章节:初识 Flask · 路由(Routing)艺术


1. 为什么必须用虚拟环境?

1.1 全局安装的致命坑

想象一个场景:

场景:你的老项目A依赖Flask 2.0,新项目B要尝鲜Flask 3.0的异步装饰器
→ 老项目全局更新Flask?直接报兼容性错误
→ 新项目迁就全局版本?错过新特性
→ 😱 只能拆机器?当然不是!

虚拟环境是解药:它为每个项目创建独立的「Python环境盒子」,里面的依赖、解释器路径完全隔离,互不干扰。

1.2 Python 3.3+ 自带的 venv 就够了

以前可能用 virtualenvPipenv,但现在 Python 官方已经把轻量、好用的 venv 内置进去(3.3+),无需额外安装任何第三方工具。

常用创建&激活命令

# 1. 创建虚拟环境(推荐用当前目录下的 venv 文件夹作为容器)
python -m venv venv

# 2. 激活虚拟环境(根据终端选择)
# ✅ Windows PowerShell(推荐先执行 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 解决权限限制)
.\venv\Scripts\Activate.ps1
# ✅ Windows CMD
venv\Scripts\activate.bat
# ✅ macOS / Linux(bash/zsh通用)
source venv/bin/activate

# 3. 验证激活成功(命令提示符前会带 (venv) 前缀)
(venv) PS D:\code_daoman\daoman_blog>

2. 安装 Flask 及规范依赖管理

2.1 基础起步:只装 Flask

如果是写练习项目,直接安装核心包就行:

pip install flask

2.2 实战推荐:安装常用扩展

做正式项目(比如这一系列的 DaoMan 博客),我们会用到这些高频扩展:

pip install \
flask \                 # 核心 Web 框架
flask-sqlalchemy \      # ORM 数据库操作
flask-login \           # 用户认证
flask-wtf \             # 表单验证+CSRF防护
flask-migrate \         # Alembic 数据库迁移封装
flask-cors \            # 跨域请求处理
python-dotenv \         # 环境变量加载
email-validator         # 邮箱格式验证

2.3 依赖清单:团队/部署必备

每次安装/卸载依赖后,务必更新依赖清单,方便在新机器一键恢复:

# 导出当前环境的依赖到 requirements.txt
pip freeze > requirements.txt

# 新机器/新克隆项目后,一键恢复所有依赖
pip install -r requirements.txt

更推荐的 requirements.txt 写法

全量导出 pip freeze 可能会带一些不必要的间接依赖,更推荐手动写核心依赖 + 版本范围,既清晰又安全(避免间接依赖的小版本 bug):

Flask>=3.0.0,<4.0.0
Flask-SQLAlchemy>=3.1.0,<4.0.0
Flask-Login>=0.6.3,<1.0.0
Flask-WTF>=1.2.0,<2.0.0
Flask-Migrate>=4.0.0,<5.0.0
Flask-CORS>=4.0.0,<5.0.0
python-dotenv>=1.0.0,<2.0.0
email-validator>=2.0.0,<3.0.0

3. 项目初始化(DaoMan 博客为例)

3.1 快速搭建项目骨架

按下面的命令一步步走,就能生成标准的 Flask 项目目录:

# 1. 创建项目根目录并进入
mkdir daoman_blog
cd daoman_blog

# 2. 初始化虚拟环境(记得激活!)
python -m venv venv
# 根据终端选择激活命令:.\venv\Scripts\Activate.ps1 或 source venv/bin/activate

# 3. 创建目录结构(手动 mkdir 或按下面的树形结构创建)

3.2 推荐的标准 Flask 目录结构

daoman_blog/
├── app/                       # 应用核心代码包(重要!单独放代码)
│   ├── __init__.py           # 应用工厂入口(create_app()函数)
│   ├── extensions.py         # 扩展统一初始化(db/login_manager等)
│   ├── routes/               # 路由模块(用 Blueprint 拆分)
│   │   ├── __init__.py
│   │   ├── main.py           # 首页/通用路由
│   │   ├── auth.py           # 登录/注册/登出路由
│   │   └── articles.py       # 文章相关路由
│   ├── models/               # ORM 数据模型
│   │   ├── __init__.py
│   │   └── user.py
│   ├── templates/            # Jinja2 模板文件
│   │   ├── base.html         # 基础母模板(所有页面继承)
│   │   ├── index.html        # 首页
│   │   └── auth/
│   │       └── login.html    # 登录页
│   └── static/               # 静态资源(CSS/JS/图片/上传文件)
│       ├── css/
│       ├── js/
│       └── uploads/
├── migrations/               # Alembic 数据库迁移脚本(自动生成)
├── tests/                    # 测试代码(pytest)
├── .env                      # 实际环境变量(含密钥,**绝对不上传Git**)
├── .env.example              # 环境变量模板(上传Git,给协作者参考)
├── .gitignore                # Git 忽略文件配置
├── requirements.txt          # 依赖清单
├── config.py                 # 项目配置文件(开发/测试/生产分离)
└── run.py                    # 启动脚本

💡 提示:初学者可以先手动创建这些文件夹和空文件,后续章节会逐步填充内容。保持结构清晰比什么都重要。


4. 应用工厂模式(Flask 官方推荐)

为什么要用应用工厂?

  • 🧩 支持多环境切换:开发、测试、生产配置一键搞定
  • 🔁 避免循环导入:比如 routes 导入 db,db 导入 app 这类问题
  • 🧪 方便编写测试:可以创建多个独立的测试实例

4.1 第一步:统一初始化扩展

新建 app/extensions.py,把所有扩展先实例化,暂时不绑定 app

# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect

# 实例化所有扩展(不带app参数)
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()
csrf = CSRFProtect()

# 配置 login_manager
login_manager.login_view = "auth.login"  # 未登录用户自动跳转到登录页
login_manager.login_message = "请先登录后再访问该页面哦~"
login_manager.login_message_category = "info"  # 消息提示的样式类(Bootstrap用)

4.2 第二步:应用工厂函数

新建 app/__init__.py,编写 create_app(config_name) 函数:

# app/__init__.py
from flask import Flask
from config import config
from app.extensions import db, login_manager, migrate, csrf

def create_app(config_name="development"):
    # 1. 创建 Flask 实例
    app = Flask(__name__)

    # 2. 加载对应环境的配置
    app.config.from_object(config[config_name])

    # 3. 绑定扩展到当前 app
    db.init_app(app)
    login_manager.init_app(app)
    migrate.init_app(app, db)
    csrf.init_app(app)

    # 4. 注册 Blueprint(路由拆分)
    from app.routes.main import main_bp
    from app.routes.auth import auth_bp
    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp, url_prefix="/auth")  # 加前缀避免路由冲突

    # 5. (可选)添加简单的错误处理

    # 6. 返回配置好的 app 实例
    return app

4.3 第三步:多环境配置文件

新建 config.py,分离开发/测试/生产的配置:

# config.py
import os
from dotenv import load_dotenv

# 加载项目根目录的 .env 文件
load_dotenv()

class BaseConfig:
    """基础配置(所有环境共用)"""
    SECRET_KEY = os.getenv("SECRET_KEY", "dev-secret-key-123-CHANGE-ME-IN-PRODUCTION")
    SQLALCHEMY_TRACK_MODIFICATIONS = False  # 关闭不必要的数据库修改追踪
    UPLOAD_FOLDER = os.path.join(os.path.dirname(__file__), "app/static/uploads")

class DevelopmentConfig(BaseConfig):
    """开发环境配置"""
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.getenv("DEV_DATABASE_URL", "sqlite:///daoman_dev.db")

class ProductionConfig(BaseConfig):
    """生产环境配置"""
    DEBUG = False
    SQLALCHEMY_DATABASE_URI = os.getenv("PROD_DATABASE_URL", "postgresql://user:pass@localhost/daoman_prod")

class TestingConfig(BaseConfig):
    """测试环境配置"""
    TESTING = True
    SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"  # 内存数据库,测试完自动清空
    WTF_CSRF_ENABLED = False  # 测试时关闭 CSRF 验证

# 配置字典,供 create_app() 调用
config = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
    "testing": TestingConfig,
    "default": DevelopmentConfig,
}

4.4 第四步:启动脚本

新建 run.py,作为项目的入口文件:

# run.py
import os
from app import create_app

# 从环境变量读取配置名,默认用开发环境
config_name = os.getenv("FLASK_ENV", "development")
app = create_app(config_name)

if __name__ == "__main__":
    app.run(
        host="127.0.0.1",  # 本地访问
        port=5000,
        debug=config[config_name].DEBUG,  # 同步环境的DEBUG配置
    )

5. 敏感信息与 Git 规范

5.1 用 .env 管理密钥和敏感配置

直接把密钥写在 config.py非常危险,会被上传到 Git 公开!必须用 python-dotenv 加载外部的 .env 文件。

.env 和 .env.example 的区别

# .env(实际使用的,**绝对不能上传 Git**)
SECRET_KEY=230894d23c892b123a123d789f123a456c789d01
DEV_DATABASE_URL=sqlite:///daoman_dev.db
PROD_DATABASE_URL=postgresql://daoman_user:daoman_pass123@127.0.0.1:5432/daoman_prod
FLASK_ENV=development
# .env.example(模板,**必须上传 Git**,给协作者参考)
SECRET_KEY=change-this-to-a-strong-random-secret
DEV_DATABASE_URL=sqlite:///daoman_dev.db
PROD_DATABASE_URL=postgresql://user:pass@localhost/db_name
FLASK_ENV=development

5.2 .gitignore 配置

新建 .gitignore,忽略所有不必要的文件:

# .gitignore
# 虚拟环境
venv/
.venv/

# Python 缓存
__pycache__/
*.py[cod]
*$py.class

# 数据库
*.db
*.sqlite
*.sqlite3

# 环境变量
.env
.env.local

# IDE 配置
.vscode/
.idea/
*.swp
*.swo

# 上传文件(可选)
app/static/uploads/*
!app/static/uploads/.gitkeep  # 保留空文件夹到Git

# 测试覆盖率
.coverage
htmlcov/

6. 小结与验证清单

6.1 项目初始化快速验证清单

现在你应该已经完成了所有步骤,按下面的清单验证是否成功:

✅ 虚拟环境已创建并激活
✅ requirements.txt 已生成或手动编写
✅ 标准目录结构已建立
✅ 应用工厂模式已实现
✅ .env 和 .env.example 已创建
✅ .gitignore 已配置
✅ 运行 python run.py 能正常启动(访问 http://127.0.0.1:5000 会显示404,因为还没写首页路由~)

6.2 最佳实践提醒

💡 敲黑板:从第一天起就使用虚拟环境应用工厂模式!虽然最小应用(比如 hello.py)可以直接写在一个文件里,但养成规范习惯能避免以后重构的巨大痛苦。


🔗 扩展阅读