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配置
创建Flask项目:
- File → New Project → Flask
- 选择Python解释器
- 配置项目结构
运行配置:
- Run → Edit Configurations
- 添加Flask Server配置
- 设置环境变量
调试配置:
- 设置断点
- 使用调试模式运行
- 查看变量和调用栈
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开发环境的搭建和配置,包括:
- Python环境:版本选择、包管理工具、虚拟环境管理
- Flask安装:基础安装、扩展管理、依赖管理
- 开发工具:IDE配置、命令行工具、调试环境
- 项目结构:从小型到大型项目的组织方式
- 配置管理:多环境配置、环境变量管理
- 代码质量:格式化、检查、类型检查、预提交钩子
- 部署准备:Docker配置、WSGI服务器配置
良好的开发环境配置是高效开发的基础,合理的项目结构和代码质量工具能够显著提升开发效率和代码质量。
下一章预告
下一章我们将学习Flask路由与视图,包括:
- 路由系统详解
- URL规则和参数
- HTTP方法处理
- 视图函数设计
- 错误处理
- 蓝图使用
练习题
- 环境搭建:使用pipenv创建一个Flask项目环境
- 项目结构:设计一个博客应用的项目结构
- 配置管理:创建开发、测试、生产三套配置
- 代码质量:配置black、flake8、mypy工具链
- Docker部署:编写Dockerfile和docker-compose.yml文件