一、环境搭建
Flask对Python版本兼容性较好,但推荐使用较新的版本以获得更好的特性支持:
-
Python版本:推荐Python 3.6及以上
-
安装核心依赖 :
bash# 基础安装(Flask框架) pip install flask # 常用扩展(根据需求选择) pip install flask-sqlalchemy # ORM工具(数据库操作) pip install flask-migrate # 数据库迁移(管理schema变化) pip install flask-restful # 快速构建RESTful API(或用flask-restx) pip install flask-jwt-extended # JWT认证 pip install python-dotenv # 加载.env环境变量 pip install pytest # 测试工具 pip install gunicorn # 生产环境WSGI服务器
二、项目结构(推荐)
Flask没有强制的目录结构,但合理的结构能避免代码混乱,推荐如下(以RESTful API项目为例):
my_flask_project/
├── app/ # 核心应用代码
│ ├── __init__.py # 应用初始化(创建Flask实例、注册扩展)
│ ├── config.py # 配置类(区分开发/测试/生产环境)
│ ├── extensions.py # 扩展实例化(如db、jwt,避免循环导入)
│ ├── api/ # API模块(按功能拆分蓝图)
│ │ ├── __init__.py
│ │ ├── users.py # 用户相关路由(蓝图)
│ │ └── items.py # 商品相关路由(蓝图)
│ ├── models/ # 数据库模型(SQLAlchemy类)
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── item.py
│ ├── services/ # 业务逻辑层(拆分视图函数中的复杂逻辑)
│ ├── schemas/ # 数据验证/序列化(可用marshmallow)
│ └── utils/ # 工具函数(如异常处理、权限校验)
├── migrations/ # 数据库迁移文件(由flask-migrate生成)
├── tests/ # 测试代码
│ ├── __init__.py
│ ├── test_users.py
│ └── test_items.py
├── .env # 环境变量(敏感信息,不提交到代码库)
├── .env.example # 环境变量示例(提交到代码库)
├── requirements.txt # 依赖清单
├── run.py # 应用启动入口
└── README.md
三、核心配置
Flask的配置灵活但需手动管理,以下是必须配置的核心内容:
1. 应用初始化与扩展管理
为避免循环导入(Flask常见问题),推荐将扩展实例化与应用初始化分离:
-
步骤1:在
extensions.py
中实例化扩展python# app/extensions.py from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_jwt_extended import JWTManager # 先实例化扩展,不绑定应用 db = SQLAlchemy() migrate = Migrate() jwt = JWTManager()
-
步骤2:在
__init__.py
中创建Flask实例并绑定扩展python# app/__init__.py from flask import Flask from app.config import config_by_name # 导入配置类 from app.extensions import db, migrate, jwt def create_app(config_name="dev"): app = Flask(__name__) # 加载配置(从配置类) app.config.from_object(config_by_name[config_name]) # 绑定扩展到应用 db.init_app(app) migrate.init_app(app, db) jwt.init_app(app) # 注册蓝图(API路由) from app.api.users import users_bp from app.api.items import items_bp app.register_blueprint(users_bp, url_prefix="/api/users") app.register_blueprint(items_bp, url_prefix="/api/items") return app
2. 配置管理(多环境隔离)
使用配置类区分开发、测试、生产环境,敏感信息通过环境变量加载(避免硬编码):
python
# app/config.py
import os
from dotenv import load_dotenv
# 加载.env文件中的环境变量
load_dotenv()
class Config:
# 通用配置
SECRET_KEY = os.getenv("SECRET_KEY") # 用于会话、加密等(必须设置)
SQLALCHEMY_TRACK_MODIFICATIONS = False # 禁用SQLAlchemy的修改跟踪(提升性能)
class DevelopmentConfig(Config):
DEBUG = True # 开发模式(自动重载、显示错误详情)
SQLALCHEMY_DATABASE_URI = os.getenv("DEV_DATABASE_URL", "sqlite:///dev.db") # 开发数据库
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = os.getenv("TEST_DATABASE_URL", "sqlite:///test.db") # 测试数据库
JWT_SECRET_KEY = "test-secret-key" # 测试环境JWT密钥(可简化)
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL") # 生产数据库(如PostgreSQL)
# 生产环境需强制HTTPS(配合Flask-Talisman)
SESSION_COOKIE_SECURE = True # Cookie仅通过HTTPS传输
REMEMBER_COOKIE_SECURE = True
# 配置映射(便于通过环境变量切换)
config_by_name = {
"dev": DevelopmentConfig,
"test": TestingConfig,
"prod": ProductionConfig
}
对应的.env
文件示例:
env
# .env
SECRET_KEY=your_prod_secret_key_here
DEV_DATABASE_URL=sqlite:///dev.db
DATABASE_URL=postgresql://user:password@localhost:5432/prod_db
3. 数据库配置与迁移
使用Flask-SQLAlchemy
操作数据库,Flask-Migrate
管理schema变更:
-
定义模型(如用户模型)
python# app/models/user.py from app.extensions import db from datetime import datetime class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) def __repr__(self): return f"<User {self.username}>"
-
初始化迁移环境
bash# 设置FLASK_APP入口(Windows用set,Linux/macOS用export) export FLASK_APP=run.py # 初始化迁移(仅首次) flask db init # 创建迁移脚本(检测模型变化) flask db migrate -m "initial migration" # 应用迁移到数据库 flask db upgrade
4. 路由与蓝图(拆分API)
使用蓝图(Blueprint)拆分不同模块的路由,避免单文件臃肿:
python
# app/api/users.py
from flask import Blueprint, request, jsonify
from app.models.user import User
from app.extensions import db
# 创建蓝图
users_bp = Blueprint("users", __name__)
# 定义路由(获取所有用户)
@users_bp.get("/")
def get_users():
users = User.query.all()
return jsonify([{"id": u.id, "username": u.username} for u in users])
# 创建用户
@users_bp.post("/")
def create_user():
data = request.get_json() # 获取JSON请求体
if not data or "username" not in data:
return jsonify({"error": "Missing username"}), 400 # 400错误:请求参数错误
new_user = User(username=data["username"], email=data.get("email"))
db.session.add(new_user)
db.session.commit() # 提交事务
return jsonify({"id": new_user.id, "username": new_user.username}), 201 # 201:创建成功
5. 应用启动入口(run.py)
python
# run.py
import os
from app import create_app
# 从环境变量获取配置名(默认开发环境)
config_name = os.getenv("FLASK_ENV", "dev")
app = create_app(config_name=config_name)
if __name__ == "__main__":
# 开发环境启动(默认端口5000)
app.run(host="0.0.0.0", debug=app.config["DEBUG"])
四、关键注意点
1. 配置安全与敏感信息
- 禁止生产环境启用DEBUG模式 :
DEBUG=True
会暴露详细错误信息(包括代码堆栈),且允许通过浏览器执行代码,存在严重安全风险。 - SECRET_KEY必须保密 :用于会话签名、密码重置令牌等,泄露会导致安全漏洞(生产环境需用强随机字符串,可通过
python -c "import secrets; print(secrets.token_hex(32))"
生成)。 - 环境变量隔离 :开发/测试/生产的配置(如数据库地址、API密钥)必须通过
.env
或系统环境变量加载,绝对不能硬编码在代码中。
2. 数据库操作最佳实践
-
避免循环导入 :模型和扩展必须通过
extensions.py
的方式分离实例化,否则会导致db
未初始化的错误。 -
事务管理 :数据库写操作(新增/修改/删除)必须用
db.session.commit()
提交,失败时用db.session.rollback()
回滚,避免数据不一致:pythontry: db.session.add(new_user) db.session.commit() except Exception as e: db.session.rollback() return jsonify({"error": str(e)}), 500
-
连接池配置 :生产环境需配置数据库连接池(避免频繁创建连接),以PostgreSQL为例:
python# 在ProductionConfig中添加 SQLALCHEMY_ENGINE_OPTIONS = { "pool_size": 10, # 固定连接数 "max_overflow": 20, # 临时额外连接数 "pool_recycle": 300, # 连接超时时间(秒),避免数据库主动关闭连接 }
3. 路由与视图函数
-
避免视图函数臃肿 :复杂业务逻辑应拆分到
services
层,视图函数仅负责接收请求、调用服务、返回响应:python# 反例:视图函数包含过多逻辑 @users_bp.post("/") def create_user(): data = request.get_json() if not data: ... # 验证 if User.query.filter_by(username=data["username"]).first(): ... # 检查重复 new_user = User(...) # 创建对象 db.session.add(...) # 保存 # ... 更多逻辑 # 正例:拆分到服务层 @users_bp.post("/") def create_user(): data = request.get_json() result = user_service.create_user(data) # 调用服务 if result["success"]: return jsonify(result["data"]), 201 return jsonify({"error": result["error"]}), 400
-
请求数据验证 :Flask本身不提供自动验证,需手动检查或使用
marshmallow
/pydantic
:python# 用marshmallow验证 from marshmallow import Schema, fields, validate, ValidationError class UserSchema(Schema): username = fields.Str(required=True, validate=validate.Length(min=3, max=20)) email = fields.Email(required=True) @users_bp.post("/") def create_user(): try: data = UserSchema().load(request.get_json()) # 验证并加载数据 except ValidationError as err: return jsonify({"errors": err.messages}), 400
4. 异步处理与性能
- Flask默认是同步框架,处理耗时操作(如IO、第三方API调用)会阻塞主线程,导致并发性能差。可通过以下方式优化:
- 使用
Celery
处理异步任务(如邮件发送、数据导出)。 - 对于简单异步需求,可使用
flask-async
扩展(基于Python的asyncio
),但需注意与同步扩展的兼容性。
- 使用
5. 错误处理
-
避免直接返回500错误(默认错误页),应自定义异常处理器,返回结构化响应:
python# app/utils/errors.py from flask import jsonify from werkzeug.exceptions import HTTPException def register_error_handlers(app): # 处理HTTP异常(如404、400) @app.errorhandler(HTTPException) def handle_http_exception(e): return jsonify({"error": e.description}), e.code # 处理其他异常 @app.errorhandler(Exception) def handle_generic_exception(e): app.logger.error(f"Unhandled exception: {str(e)}") # 记录日志 return jsonify({"error": "Internal server error"}), 500 # 不暴露细节 # 在create_app中注册 def create_app(...): # ... from app.utils.errors import register_error_handlers register_error_handlers(app)
6. 测试与部署
-
测试 :使用
pytest
和Flask的test_client
编写测试,确保覆盖核心逻辑:python# tests/test_users.py import pytest from app import create_app from app.extensions import db @pytest.fixture def client(): app = create_app("test") with app.test_client() as client: with app.app_context(): # 激活应用上下文 db.create_all() # 创建测试表 yield client db.drop_all() # 清理 def test_create_user(client): response = client.post("/api/users/", json={"username": "test", "email": "test@example.com"}) assert response.status_code == 201 assert response.json["username"] == "test"
-
部署:
-
开发环境:
python run.py
(依赖DEBUG=True
自动重载)。 -
生产环境:用
gunicorn
作为WSGI服务器(Flask内置服务器不适合生产):bash# 安装gunicorn后启动(worker数建议为CPU核心数*2+1) gunicorn -w 4 -b 0.0.0.0:8000 "run:app"
-
配合Nginx反向代理:处理静态文件、SSL终止、负载均衡等,示例配置:
nginxserver { listen 443 ssl; server_name your-domain.com; ssl_certificate /path/to/cert.pem; location / { proxy_pass http://127.0.0.1:8000; # 转发到gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
-
7. Flask上下文机制
Flask的上下文(请求上下文、应用上下文)是容易踩坑的点:
-
请求上下文 :
request
(请求数据)、session
(会话)仅在视图函数或请求处理过程中可用,不可在后台任务(如Celery)中直接使用。 -
应用上下文 :
current_app
(当前应用实例)、g
(临时存储)需通过app.app_context()
激活后才能在非视图函数中使用:python# 正确:在非视图函数中使用current_app with app.app_context(): print(current_app.config["SECRET_KEY"])