第2章 环境搭建与开发工具

80 阅读4分钟

第2章 环境搭建与开发工具

2.1 Python环境准备

2.1.1 Python版本选择

Flask支持Python 3.7+版本,推荐使用Python 3.9或更高版本:

# 检查Python版本
python --version
python3 --version

# 如果需要安装Python,推荐使用pyenv管理多版本
# Linux/Mac安装pyenv
curl https://pyenv.run | bash

# 安装Python 3.11
pyenv install 3.11.0
pyenv global 3.11.0

2.1.2 包管理工具

# pip升级
python -m pip install --upgrade pip

# 安装pipenv(推荐)
pip install pipenv

# 或者使用poetry
curl -sSL https://install.python-poetry.org | python3 -

2.2 虚拟环境管理

2.2.1 使用venv创建虚拟环境

# 创建项目目录
mkdir flask_project
cd flask_project

# 创建虚拟环境
python -m venv venv

# 激活虚拟环境
# Linux/Mac
source venv/bin/activate

# Windows Command Prompt
venv\Scripts\activate.bat

# Windows PowerShell
venv\Scripts\Activate.ps1

# 验证虚拟环境
which python  # Linux/Mac
where python  # Windows

2.2.2 使用pipenv管理环境

# 创建项目并初始化Pipfile
mkdir flask_project
cd flask_project
pipenv --python 3.11

# 激活虚拟环境
pipenv shell

# 安装依赖
pipenv install flask
pipenv install pytest --dev  # 开发依赖

# 生成requirements.txt
pipenv requirements > requirements.txt

# 从Pipfile安装依赖
pipenv install

2.2.3 使用poetry管理项目

# 创建新项目
poetry new flask_project
cd flask_project

# 或在现有目录初始化
poetry init

# 添加依赖
poetry add flask
poetry add pytest --group dev

# 激活虚拟环境
poetry shell

# 安装依赖
poetry install

2.3 Flask安装与配置

2.3.1 基础安装

# 安装Flask
pip install Flask

# 验证安装
python -c "import flask; print(flask.__version__)"

# 安装常用扩展
pip install Flask-SQLAlchemy
pip install Flask-Migrate
pip install Flask-WTF
pip install Flask-Login
pip install Flask-Mail

2.3.2 requirements.txt管理

# requirements.txt
Flask==2.3.3
Flask-SQLAlchemy==3.0.5
Flask-Migrate==4.0.5
Flask-WTF==1.1.1
Flask-Login==0.6.3
Flask-Mail==0.9.1
Flask-Admin==1.6.1
Flask-RESTful==0.3.10
Flask-CORS==4.0.0
Flask-Caching==2.1.0
Werkzeug==2.3.7
Jinja2==3.1.2
WTForms==3.0.1
SQLAlchemy==2.0.21
Alembic==1.12.0

# 安装依赖 pip install -r requirements.txt

# 更新requirements.txt pip freeze > requirements.txt


### 2.3.3 开发依赖管理

# requirements-dev.txt -r requirements.txt pytest==7.4.2 pytest-cov==4.1.0 flake8==6.1.0 black==23.9.1 mypy==1.5.1 pre-commit==3.4.0 flask-testing==0.8.1


2.4 开发工具配置
----------

### 2.4.1 VS Code配置

// .vscode/settings.json {     "python.defaultInterpreterPath": "./venv/bin/python",     "python.linting.enabled": true,     "python.linting.flake8Enabled": true,     "python.formatting.provider": "black",     "python.formatting.blackArgs": ["--line-length=88"],     "python.testing.pytestEnabled": true,     "python.testing.pytestArgs": ["tests"],     "files.associations": {         "*.html": "jinja-html"     },     "emmet.includeLanguages": {         "jinja-html": "html"     } }

// .vscode/launch.json
{
    "version""0.2.0",
    "configurations": [
        {
            "name""Flask Debug",
            "type""python",
            "request""launch",
            "program""${workspaceFolder}/run.py",
            "env": {
                "FLASK_ENV""development",
                "FLASK_DEBUG""1"
            },
            "args": [],
            "jinja": true,
            "console""integratedTerminal"
        }
    ]
}
```

推荐的VS Code扩展:

*   • Python
*   • Flask Snippets
*   • Jinja
*   • SQLite Viewer
*   • REST Client
*   • GitLens

### 2.4.2 PyCharm配置

1.  1\. **创建Flask项目**:
    *   • File → New Project → Flask
    *   • 选择Python解释器
    *   • 配置项目结构
2.  2\. **运行配置**:
    *   • Run → Edit Configurations
    *   • 添加Flask Server配置
    *   • 设置环境变量
3.  3\. **调试配置**:
    *   • 设置断点
    *   • 使用调试模式运行
    *   • 查看变量和调用栈

### 2.4.3 命令行工具

```
# Flask CLI命令
flask --help

# 设置环境变量
export FLASK_APP=app.py
export FLASK_ENV=development

# 运行应用
flask run
flask run --host=0.0.0.0 --port=8000

# 进入Shell
flask shell

# 数据库操作
flask db init
flask db migrate -m "Initial migration"
flask db upgrade
```

2.5 项目结构最佳实践
------------

### 2.5.1 小型项目结构

```
flask_app/
├── app.py                 # 主应用文件
├── config.py              # 配置文件
├── requirements.txt       # 依赖列表
├── .env                   # 环境变量
├── .gitignore            # Git忽略文件
├── README.md             # 项目说明
├── templates/            # 模板目录
│   ├── base.html
│   ├── index.html
│   └── about.html
├── static/               # 静态文件
│   ├── css/
│   │   └── style.css
│   ├── js/
│   │   └── main.js
│   └── images/
└── tests/                # 测试文件
    ├── __init__.py
    ├── test_app.py
    └── conftest.py
```

### 2.5.2 中型项目结构

```
flask_project/
├── app/                   # 应用包
│   ├── __init__.py       # 应用工厂
│   ├── models.py         # 数据模型
│   ├── views.py          # 视图函数
│   ├── forms.py          # 表单类
│   ├── utils.py          # 工具函数
│   ├── templates/        # 模板文件
│   └── static/           # 静态文件
├── migrations/           # 数据库迁移
├── tests/                # 测试文件
├── config.py             # 配置文件
├── requirements.txt      # 依赖列表
├── run.py               # 启动脚本
└── .env                 # 环境变量
```

### 2.5.3 大型项目结构(蓝图)

```
flask_project/
├── app/
│   ├── __init__.py       # 应用工厂
│   ├── models/           # 数据模型
│   │   ├── __init__.py
│   │   ├── user.py
│   │   └── post.py
│   ├── main/             # 主蓝图
│   │   ├── __init__.py
│   │   ├── views.py
│   │   └── forms.py
│   ├── auth/             # 认证蓝图
│   │   ├── __init__.py
│   │   ├── views.py
│   │   └── forms.py
│   ├── api/              # API蓝图
│   │   ├── __init__.py
│   │   ├── users.py
│   │   └── posts.py
│   ├── templates/        # 模板文件
│   │   ├── base.html
│   │   ├── main/
│   │   ├── auth/
│   │   └── errors/
│   ├── static/           # 静态文件
│   └── utils/            # 工具模块
│       ├── __init__.py
│       ├── decorators.py
│       └── helpers.py
├── migrations/           # 数据库迁移
├── tests/                # 测试文件
│   ├── __init__.py
│   ├── test_models.py
│   ├── test_views.py
│   └── test_api.py
├── config.py             # 配置文件
├── requirements.txt      # 生产依赖
├── requirements-dev.txt  # 开发依赖
├── run.py               # 启动脚本
├── .env                 # 环境变量
├── .gitignore           # Git忽略
├── Dockerfile           # Docker配置
├── docker-compose.yml   # Docker Compose
└── README.md            # 项目文档
```

2.6 配置管理
--------

### 2.6.1 配置文件设计

```
# config.py
import os
from datetime import timedelta

basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
    """基础配置类"""
    SECRET_KEY = os.environ.get('SECRET_KEY'or 'dev-secret-key'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = int(os.environ.get('MAIL_PORT'or 587)
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS''true').lower() in ['true''on''1']
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    ADMIN_EMAIL = os.environ.get('ADMIN_EMAIL')
    
    # 分页配置
    POSTS_PER_PAGE = 10
    USERS_PER_PAGE = 20
    
    # 上传配置
    UPLOAD_FOLDER = os.path.join(basedir, 'uploads')
    MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 16MB
    
    # 缓存配置
    CACHE_TYPE = 'simple'
    CACHE_DEFAULT_TIMEOUT = 300
    
    # JWT配置
    JWT_SECRET_KEY = os.environ.get('JWT_SECRET_KEY'or 'jwt-secret'
    JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=1)
    
    @staticmethod
    def init_app(app):
        pass

class DevelopmentConfig(Config):
    """开发环境配置"""
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL'or \
        'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
    
    # 开发环境邮件配置
    MAIL_SUPPRESS_SEND = False
    TESTING = False

class TestingConfig(Config):
    """测试环境配置"""
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL'or \
        'sqlite://'
    WTF_CSRF_ENABLED = False
    MAIL_SUPPRESS_SEND = True

class ProductionConfig(Config):
    """生产环境配置"""
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL'or \
        'sqlite:///' + os.path.join(basedir, 'data.sqlite')
    
    # 生产环境安全配置
    SSL_REDIRECT = True
    
    @classmethod
    def init_app(cls, app):
        Config.init_app(app)
        
        # 日志配置
        import logging
        from logging.handlers import RotatingFileHandler
        
        if not app.debug:
            if not os.path.exists('logs'):
                os.mkdir('logs')
            file_handler = RotatingFileHandler('logs/app.log', maxBytes=10240, backupCount=10)
            file_handler.setFormatter(logging.Formatter(
                '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
            file_handler.setLevel(logging.INFO)
            app.logger.addHandler(file_handler)
            app.logger.setLevel(logging.INFO)
            app.logger.info('Application startup')

# 配置字典
config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}
```

### 2.6.2 环境变量管理

```
# .env文件
FLASK_APP=run.py
FLASK_ENV=development
SECRET_KEY=your-secret-key-here
DATABASE_URL=sqlite:///app.db
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USE_TLS=1
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password
ADMIN_EMAIL=admin@example.com

# 加载环境变量 from dotenv import load_dotenv

load_dotenv()  # 加载.env文件

# 或者在应用工厂中加载 def create_app(config_name=None):     if config_name is None:         config_name = os.environ.get('FLASK_CONFIG', 'default')          app = Flask(name)     app.config.from_object(config[config_name])     config[config_name].init_app(app)          return app


2.7 调试和测试环境
-----------

### 2.7.1 调试配置

# 启用调试模式 app = Flask(name) app.config['DEBUG'] = True

# 或通过环境变量 os.environ['FLASK_ENV'] = 'development' os.environ['FLASK_DEBUG'] = '1'

# 自定义调试配置 if app.debug:     # 开发环境特定配置     app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0  # 禁用静态文件缓存          # 启用SQL查询日志     import logging     logging.basicConfig()     logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)


### 2.7.2 日志配置

# logging_config.py import logging import os from logging.handlers import RotatingFileHandler, SMTPHandler

def setup_logging(app):     if not app.debug and not app.testing:         # 文件日志         if not os.path.exists('logs'):             os.mkdir('logs')                  file_handler = RotatingFileHandler(             'logs/app.log', maxBytes=10240, backupCount=10)         file_handler.setFormatter(logging.Formatter(             '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))         file_handler.setLevel(logging.INFO)         app.logger.addHandler(file_handler)                  # 邮件日志(错误级别)         if app.config.get('MAIL_SERVER'):             auth = None             if app.config.get('MAIL_USERNAME') or app.config.get('MAIL_PASSWORD'):                 auth = (app.config.get('MAIL_USERNAME'), app.config.get('MAIL_PASSWORD'))                          secure = None             if app.config.get('MAIL_USE_TLS'):                 secure = ()                          mail_handler = SMTPHandler(                 mailhost=(app.config.get('MAIL_SERVER'), app.config.get('MAIL_PORT')),                 fromaddr='no-reply@' + app.config.get('MAIL_SERVER'),                 toaddrs=app.config.get('ADMIN_EMAIL'),                 subject='Application Error',                 credentials=auth,                 secure=secure             )             mail_handler.setLevel(logging.ERROR)             app.logger.addHandler(mail_handler)                  app.logger.setLevel(logging.INFO)         app.logger.info('Application startup')


### 2.7.3 测试环境配置

# tests/conftest.py import pytest import tempfile import os from app import create_app, db from app.models import User

@pytest.fixture def app():     """创建测试应用"""     db_fd, db_path = tempfile.mkstemp()          app = create_app('testing')     app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}'     app.config['TESTING'] = True     app.config['WTF_CSRF_ENABLED'] = False          with app.app_context():         db.create_all()         yield app         db.drop_all()          os.close(db_fd)     os.unlink(db_path)

@pytest.fixture def client(app):     """创建测试客户端"""     return app.test_client()

@pytest.fixture def runner(app):     """创建CLI测试运行器"""     return app.test_cli_runner()

@pytest.fixture def user(app):     """创建测试用户"""     user = User(username='testuser', email='test@example.com')     user.set_password('testpass')     db.session.add(user)     db.session.commit()     return user


2.8 代码质量工具
----------

### 2.8.1 代码格式化

# 安装black pip install black

# 格式化代码 black . black --line-length 88 app/

# 检查格式 black --check .

# pyproject.toml
[tool.black]
line-length = 88
target-version = ['py39']
include = '\.pyi?$'
extend-exclude = '''
(
  /(
      \.eggs
    | \.git
    | \.hg
    | \.mypy_cache
    | \.tox
    | \.venv
    | _build
    | buck-out
    | build
    | dist
    | migrations
  )/
)
'''
```

### 2.8.2 代码检查

```
# 安装flake8
pip install flake8

# 检查代码
flake8 app/

# 配置文件
# .flake8
[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude = 
    .git,
    __pycache__,
    migrations,
    venv
```

### 2.8.3 类型检查

```
# 安装mypy
pip install mypy

# 类型检查
mypy app/

# mypy.ini [mypy] python_version = 3.9 warn_return_any = True warn_unused_configs = True disallow_untyped_defs = True

[mypy-flask_sqlalchemy.*] ignore_missing_imports = True

[mypy-flask_migrate.*] ignore_missing_imports = True


### 2.8.4 Pre-commit钩子

# .pre-commit-config.yaml repos:   - repo: github.com/pre-commit/…     rev: v4.4.0     hooks:       - id: trailing-whitespace       - id: end-of-file-fixer       - id: check-yaml       - id: check-added-large-files      - repo: github.com/psf/black     rev: 23.9.1     hooks:       - id: black         language_version: python3.9      - repo: github.com/pycqa/flake…     rev: 6.1.0     hooks:       - id: flake8      - repo: github.com/pre-commit/…     rev: v1.5.1     hooks:       - id: mypy         additional_dependencies: [types-all]

# 安装pre-commit
pip install pre-commit

# 安装钩子
pre-commit install

# 手动运行
pre-commit run --all-files
```

2.9 部署准备
--------

### 2.9.1 Docker配置

```
# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非root用户
RUN useradd -m -u 1000 flask && chown -R flask:flask /app
USER flask

# 暴露端口
EXPOSE 5000

# 启动命令
CMD ["gunicorn""--bind""0.0.0.0:5000""run:app"]

# docker-compose.yml version: '3.8'

services:   web:     build: .     ports:       - "5000:5000"     environment:       - FLASK_ENV=production       - DATABASE_URL=postgresql://user:password@db:5432/flask_app     depends_on:       - db     volumes:       - ./uploads:/app/uploads      db:     image: postgres:15     environment:       - POSTGRES_DB=flask_app       - POSTGRES_USER=user       - POSTGRES_PASSWORD=password     volumes:       - postgres_data:/var/lib/postgresql/data     ports:       - "5432:5432"      redis:     image: redis:7-alpine     ports:       - "6379:6379"

volumes:   postgres_data:


### 2.9.2 WSGI服务器配置

# gunicorn_config.py bind = "0.0.0.0:5000" workers = 4 worker_class = "sync" worker_connections = 1000 max_requests = 1000 max_requests_jitter = 100 timeout = 30 keepalive = 2 preload_app = True

# 日志配置 accesslog = "-" errorlog = "-" loglevel = "info" access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'

# 进程命名 proc_name = "flask_app"

# 安全配置 limit_request_line = 4094 limit_request_fields = 100 limit_request_field_size = 8190

# 启动命令
gunicorn --config gunicorn_config.py run:app

# 或者直接指定参数
gunicorn --bind 0.0.0.0:5000 --workers 4 run:app
```

本章小结
----

本章详细介绍了Flask开发环境的搭建和配置,包括:

1.  1\. **Python环境**:版本选择、包管理工具、虚拟环境管理
2.  2\. **Flask安装**:基础安装、扩展管理、依赖管理
3.  3\. **开发工具**:IDE配置、命令行工具、调试环境
4.  4\. **项目结构**:从小型到大型项目的组织方式
5.  5\. **配置管理**:多环境配置、环境变量管理
6.  6\. **代码质量**:格式化、检查、类型检查、预提交钩子
7.  7\. **部署准备**:Docker配置、WSGI服务器配置

良好的开发环境配置是高效开发的基础,合理的项目结构和代码质量工具能够显著提升开发效率和代码质量。

下一章预告
-----

下一章我们将学习**Flask路由与视图**,包括:

*   • 路由系统详解
*   • URL规则和参数
*   • HTTP方法处理
*   • 视图函数设计
*   • 错误处理
*   • 蓝图使用

练习题
---

1.  1\. **环境搭建**:使用pipenv创建一个Flask项目环境
2.  2\. **项目结构**:设计一个博客应用的项目结构
3.  3\. **配置管理**:创建开发、测试、生产三套配置
4.  4\. **代码质量**:配置black、flake8、mypy工具链
5.  5\. **Docker部署**:编写Dockerfile和docker-compose.yml文件

推荐阅读  
配置 docker0 网桥:https://www.skillup.host/1/docker/docker\_practice/advanced\_network/docker0.md  
容器访问控制:https://www.skillup.host/1/docker/docker\_practice/advanced\_network/access\_control.md