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

发布于:2025-09-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

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. 创建Flask项目

    • File → New Project → Flask
    • 选择Python解释器
    • 配置项目结构
  2. 运行配置

    • Run → Edit Configurations
    • 添加Flask Server配置
    • 设置环境变量
  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: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
  
  - repo: https://github.com/psf/black
    rev: 23.9.1
    hooks:
      - id: black
        language_version: python3.9
  
  - repo: https://github.com/pycqa/flake8
    rev: 6.1.0
    hooks:
      - id: flake8
  
  - repo: https://github.com/pre-commit/mirrors-mypy
    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. Python环境:版本选择、包管理工具、虚拟环境管理
  2. Flask安装:基础安装、扩展管理、依赖管理
  3. 开发工具:IDE配置、命令行工具、调试环境
  4. 项目结构:从小型到大型项目的组织方式
  5. 配置管理:多环境配置、环境变量管理
  6. 代码质量:格式化、检查、类型检查、预提交钩子
  7. 部署准备:Docker配置、WSGI服务器配置

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

下一章预告

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

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

练习题

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