第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