Flask构建项目

一、环境搭建

Flask对Python版本兼容性较好,但推荐使用较新的版本以获得更好的特性支持:

  1. Python版本:推荐Python 3.6及以上

  2. 安装核心依赖

    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()回滚,避免数据不一致:

    python 复制代码
    try:
        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终止、负载均衡等,示例配置:

      nginx 复制代码
      server {
          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"])
相关推荐
万粉变现经纪人16 小时前
如何解决 pip install -r requirements.txt 私有索引未设为 trusted-host 导致拒绝 问题
开发语言·python·scrapy·flask·beautifulsoup·pandas·pip
Q_Q19632884751 天前
python+vue的在线租房 房屋租赁系统
开发语言·vue.js·spring boot·python·django·flask·node.js
空影星1 天前
GridPlayer,一个好用的多视频同步播放器
python·flask·电脑·音视频
万粉变现经纪人1 天前
如何解决 pip install -r requirements.txt 私有仓库认证失败 401 Unauthorized 问题
开发语言·python·scrapy·flask·beautifulsoup·pandas·pip
'需尽欢'2 天前
基于 Flask+Vue+MySQL的研学网站
python·mysql·flask
Q_Q5110082852 天前
python+uniapp基于微信小程序的旅游信息系统
spring boot·python·微信小程序·django·flask·uni-app·node.js
Q_Q5110082852 天前
python基于web的汽车班车车票管理系统/火车票预订系统/高铁预定系统 可在线选座
spring boot·python·django·flask·node.js·汽车·php
开心-开心急了2 天前
Flask入门教程——李辉 第三章 关键知识梳理
后端·python·flask
言之。2 天前
LiteLLM:让LLM调用变得简单统一
后端·python·flask