commit 6fb3c6c23d3b7b5bc973219a05eba8714dc2267a Author: rjb <263303411@qq.com> Date: Sun Dec 21 00:20:27 2025 +0800 first commit diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..92cfe6d --- /dev/null +++ b/.flake8 @@ -0,0 +1,19 @@ +[flake8] +# flake8配置文件 +max-line-length = 100 +exclude = + .git, + __pycache__, + .venv, + venv, + migrations, + build, + dist, + *.egg-info +ignore = + E203, # whitespace before ':' + E501, # line too long (handled by black) + W503, # line break before binary operator +per-file-ignores = + __init__.py:F401 # 允许未使用的导入 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..41a7b72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,70 @@ +# Python 虚拟环境 +.venv/ +venv/ +env/ +ENV/ +myenv/ +*.pyc +__pycache__/ +*.py[cod] +*$py.class + +# 环境变量文件 +.env +.env.local +.env.*.local + +# 数据库文件 +*.db +*.sqlite +*.sqlite3 +instance/ + +# 日志文件 +logs/ +*.log + +# 上传文件 +uploads/ +media/ + +# IDE配置 +.vscode/ +.idea/ +*.swp +*.swo +*~ +.cursor/ + +# 操作系统文件 +.DS_Store +Thumbs.db +desktop.ini + +# 测试覆盖率 +.coverage +htmlcov/ +.pytest_cache/ +.tox/ + +# 构建文件 +build/ +dist/ +*.egg-info/ + +# 迁移文件(可选,建议提交) +# migrations/ + +# 临时文件 +*.tmp +*.bak +*.swp + +# 备份文件 +backups/ +*.backup + +# 配置文件(包含敏感信息) +config.local.py +settings.local.py + diff --git a/PROJECT_STRUCTURE.md b/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..15b4eee --- /dev/null +++ b/PROJECT_STRUCTURE.md @@ -0,0 +1,154 @@ +# 项目结构说明 + +## 目录结构 + +``` +template/ +├── src/ # 源代码目录 +│ └── your_app/ # 主应用包(需要重命名为你的应用名) +│ ├── __init__.py # 应用工厂,创建Flask应用实例 +│ ├── app.py # 应用入口(可选,可直接运行) +│ ├── models/ # 数据模型 +│ │ ├── __init__.py # 导出db实例和所有模型 +│ │ └── example.py # 示例模型 +│ ├── routes/ # 路由定义 +│ │ ├── __init__.py # 主路由蓝图 +│ │ └── *.py # 其他路由模块 +│ ├── services/ # 业务逻辑层 +│ │ └── __init__.py # 服务模块初始化 +│ ├── utils/ # 工具函数 +│ │ ├── __init__.py # 工具模块初始化 +│ │ └── helpers.py # 辅助函数 +│ ├── forms/ # 表单定义(可选,如果使用WTForms) +│ │ └── __init__.py +│ ├── static/ # 静态资源(CSS、JS、图片等) +│ │ ├── css/ +│ │ ├── js/ +│ │ └── images/ +│ └── templates/ # Jinja2模板文件 +│ ├── base.html # 基础模板 +│ └── *.html # 其他模板 +│ +├── config/ # 配置管理 +│ ├── __init__.py # 配置选择器,根据环境变量选择配置 +│ ├── base.py # 基础配置类,所有环境通用配置 +│ ├── development.py # 开发环境配置 +│ ├── production.py # 生产环境配置 +│ ├── testing.py # 测试环境配置 +│ └── local.py # 本地环境配置 +│ +├── requirements/ # 依赖管理(分类管理) +│ ├── base.txt # 基础依赖(项目运行必需) +│ ├── development.txt # 开发依赖(开发工具) +│ ├── production.txt # 生产依赖(WSGI服务器等) +│ └── test.txt # 测试依赖(测试框架) +│ +├── tests/ # 测试目录 +│ ├── __init__.py +│ ├── conftest.py # pytest配置和fixtures +│ └── test_*.py # 测试文件 +│ +├── migrations/ # 数据库迁移(Flask-Migrate自动生成) +│ ├── versions/ # 迁移版本文件 +│ ├── env.py # 迁移环境配置 +│ └── alembic.ini # Alembic配置 +│ +├── logs/ # 日志目录(自动生成) +│ └── app.log # 应用日志 +│ +├── uploads/ # 上传文件目录(自动生成) +│ +├── docs/ # 文档目录 +│ ├── README.md # 文档索引 +│ ├── api/ # API文档 +│ │ └── README.md +│ ├── development/ # 开发文档 +│ │ └── README.md +│ └── deployment/ # 部署文档 +│ └── README.md +│ +├── scripts/ # 工具脚本 +│ └── init_project.py # 项目初始化脚本 +│ +├── .gitignore # Git忽略文件 +├── .flake8 # flake8代码检查配置 +├── pytest.ini # pytest测试配置 +├── env.example # 环境变量模板 +├── gunicorn.conf.py # Gunicorn生产服务器配置 +├── run_dev.py # 开发环境启动脚本 +├── run_production.py # 生产环境启动脚本(测试用) +├── README.md # 项目说明文档 +├── QUICK_START.md # 快速开始指南 +└── PROJECT_STRUCTURE.md # 本文件 +``` + +## 核心文件说明 + +### 应用工厂 (`src/your_app/__init__.py`) + +使用工厂模式创建Flask应用,支持: +- 多环境配置 +- 扩展初始化 +- 蓝图注册 +- 错误处理 + +### 配置管理 (`config/`) + +- **base.py**: 所有环境通用的配置 +- **development.py**: 开发环境(调试模式开启) +- **production.py**: 生产环境(安全配置) +- **testing.py**: 测试环境(内存数据库) +- **local.py**: 本地环境(可自定义) + +通过 `FLASK_ENV` 环境变量自动选择配置。 + +### 依赖管理 (`requirements/`) + +分类管理依赖,便于不同环境安装: +- **base.txt**: 核心依赖 +- **development.txt**: 开发工具 +- **production.txt**: 生产服务器 +- **test.txt**: 测试框架 + +### 测试 (`tests/`) + +使用pytest框架: +- **conftest.py**: 定义测试fixtures +- **test_*.py**: 测试用例 + +## 使用建议 + +### 1. 项目命名 + +将 `your_app` 替换为你的实际项目名称: +- 目录: `src/your_app` -> `src/my_project` +- 导入: `from src.your_app import ...` -> `from src.my_project import ...` + +### 2. 添加新功能 + +- **路由**: 在 `routes/` 创建新文件,定义蓝图,在 `__init__.py` 注册 +- **模型**: 在 `models/` 创建新文件,运行迁移 +- **服务**: 在 `services/` 创建业务逻辑 +- **工具**: 在 `utils/` 创建辅助函数 + +### 3. 环境配置 + +通过 `.env` 文件管理配置,不要提交到Git。 + +### 4. 数据库迁移 + +始终使用Flask-Migrate管理数据库变更: +```bash +flask db migrate -m "描述" +flask db upgrade +``` + +## 最佳实践 + +1. **代码组织**: 按功能模块组织代码,保持单一职责 +2. **配置管理**: 所有配置通过环境变量,不要硬编码 +3. **错误处理**: 统一错误处理,返回标准格式 +4. **日志记录**: 重要操作记录日志 +5. **测试覆盖**: 关键功能编写测试 +6. **文档更新**: 及时更新文档,保持同步 + diff --git a/QUICK_START.md b/QUICK_START.md new file mode 100644 index 0000000..6aa201b --- /dev/null +++ b/QUICK_START.md @@ -0,0 +1,112 @@ +# 快速开始指南 + +## 5分钟快速启动 + +### 步骤1: 复制模板 + +```bash +# 复制整个template目录 +cp -r template my_new_project +cd my_new_project +``` + +### 步骤2: 运行初始化脚本(可选) + +```bash +# 运行初始化脚本,自动配置项目 +python scripts/init_project.py +``` + +或者手动配置: + +### 步骤3: 创建虚拟环境 + +```bash +python -m venv .venv + +# Windows +.venv\Scripts\activate + +# Linux/Mac +source .venv/bin/activate +``` + +### 步骤4: 安装依赖 + +```bash +pip install -r requirements/base.txt +pip install -r requirements/development.txt +``` + +### 步骤5: 配置环境变量 + +```bash +# 复制环境变量模板 +cp env.example .env + +# 编辑.env文件,至少设置: +# SECRET_KEY=你的密钥(可以用: python -c "import secrets; print(secrets.token_hex(32))" 生成) +# DATABASE_URL=sqlite:///app.db +# FLASK_ENV=development +``` + +### 步骤6: 初始化数据库 + +```bash +flask db init +flask db migrate -m "Initial migration" +flask db upgrade +``` + +### 步骤7: 运行项目 + +```bash +python run_dev.py +``` + +访问 http://localhost:5000 查看应用! + +## 重命名项目 + +如果使用初始化脚本,会自动处理。否则手动操作: + +1. 重命名目录: `src/your_app` -> `src/your_project_name` +2. 更新以下文件中的导入路径: + - `run_dev.py` + - `run_production.py` + - `gunicorn.conf.py` + - `tests/conftest.py` + - 所有测试文件 + +## 下一步 + +- 查看 [README.md](README.md) 了解完整文档 +- 查看 [docs/](docs/) 目录了解详细文档 +- 开始编写你的业务代码! + +## 常见问题 + +### Q: 如何生成SECRET_KEY? + +```bash +python -c "import secrets; print(secrets.token_hex(32))" +``` + +### Q: 如何添加新的路由? + +1. 在 `src/your_app/routes/` 创建新的路由文件 +2. 在 `src/your_app/__init__.py` 中注册蓝图 + +### Q: 如何添加新的模型? + +1. 在 `src/your_app/models/` 创建新的模型文件 +2. 在 `src/your_app/models/__init__.py` 中导入 +3. 运行 `flask db migrate -m "描述"` 创建迁移 + +### Q: 如何运行测试? + +```bash +pip install -r requirements/test.txt +pytest +``` + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1a2bdf --- /dev/null +++ b/README.md @@ -0,0 +1,258 @@ +# Python项目模板 + +这是一个通用的Python项目模板,基于Flask框架的最佳实践,可以直接复制使用,快速启动新项目。 + +## 项目特性 + +- ✅ **标准化项目结构** - 清晰的目录组织,易于维护 +- ✅ **多环境配置管理** - 支持development/production/testing/local环境 +- ✅ **依赖分类管理** - 基础/开发/生产/测试依赖分离 +- ✅ **应用工厂模式** - 灵活的Flask应用创建方式 +- ✅ **数据库迁移支持** - 使用Flask-Migrate管理数据库版本 +- ✅ **环境变量管理** - 使用.env文件管理敏感配置 +- ✅ **完整的文档结构** - 包含API、开发、部署文档模板 +- ✅ **测试框架集成** - pytest测试配置 +- ✅ **日志系统** - 自动配置日志记录 +- ✅ **跨域支持** - CORS配置 + +## 快速开始 + +### 1. 复制模板 + +```bash +# 复制整个template目录到你的新项目位置 +cp -r template my_new_project +cd my_new_project +``` + +### 2. 初始化项目 + +```bash +# 创建虚拟环境 +python -m venv .venv + +# 激活虚拟环境 +# Windows +.venv\Scripts\activate +# Linux/Mac +source .venv/bin/activate + +# 安装依赖 +pip install -r requirements/base.txt +pip install -r requirements/development.txt +``` + +### 3. 配置环境变量 + +```bash +# 复制环境变量模板 +cp .env.example .env + +# 编辑.env文件,填入你的配置 +# 至少需要设置: +# - SECRET_KEY +# - DATABASE_URL +# - FLASK_ENV +``` + +### 4. 初始化数据库 + +```bash +# 初始化数据库迁移 +flask db init + +# 创建初始迁移 +flask db migrate -m "Initial migration" + +# 应用迁移 +flask db upgrade +``` + +### 5. 运行项目 + +```bash +# 开发模式 +python run_dev.py + +# 或使用Flask命令 +flask run +``` + +## 项目结构 + +``` +template/ +├── src/ # 源代码目录 +│ └── your_app/ # 主应用包(需要重命名) +│ ├── __init__.py # 应用工厂 +│ ├── app.py # 应用配置 +│ ├── models/ # 数据模型 +│ ├── routes/ # 路由定义 +│ ├── services/ # 业务逻辑 +│ ├── utils/ # 工具函数 +│ ├── forms/ # 表单定义(可选) +│ ├── static/ # 静态资源 +│ └── templates/ # 模板文件 +├── config/ # 配置管理 +│ ├── __init__.py # 配置选择器 +│ ├── base.py # 基础配置 +│ ├── development.py # 开发环境 +│ ├── production.py # 生产环境 +│ ├── testing.py # 测试环境 +│ └── local.py # 本地环境 +├── requirements/ # 依赖管理 +│ ├── base.txt # 基础依赖 +│ ├── development.txt # 开发依赖 +│ ├── production.txt # 生产依赖 +│ └── test.txt # 测试依赖 +├── tests/ # 测试目录 +│ ├── __init__.py +│ ├── conftest.py # pytest配置 +│ └── test_*.py # 测试文件 +├── migrations/ # 数据库迁移(自动生成) +├── logs/ # 日志目录(自动生成) +├── uploads/ # 上传文件目录(自动生成) +├── docs/ # 文档目录 +│ ├── api/ # API文档 +│ ├── development/ # 开发文档 +│ └── deployment/ # 部署文档 +├── scripts/ # 工具脚本 +│ └── init_project.py # 项目初始化脚本 +├── .env.example # 环境变量模板 +├── .gitignore # Git忽略文件 +├── run_dev.py # 开发服务器启动脚本 +├── run_production.py # 生产环境启动脚本 +└── README.md # 项目说明(本文件) +``` + +## 使用说明 + +### 重命名项目 + +1. 将 `src/your_app/` 目录重命名为你的应用名称 +2. 更新 `src/your_app/__init__.py` 中的导入路径 +3. 更新 `run_dev.py` 和 `run_production.py` 中的导入路径 +4. 更新所有文档中的项目名称 + +### 配置环境 + +通过设置 `FLASK_ENV` 环境变量来选择配置: + +```bash +# 开发环境(默认) +export FLASK_ENV=development + +# 生产环境 +export FLASK_ENV=production + +# 测试环境 +export FLASK_ENV=testing + +# 本地环境 +export FLASK_ENV=local +``` + +### 添加新功能 + +1. **添加路由**:在 `src/your_app/routes/` 创建新的路由文件 +2. **添加模型**:在 `src/your_app/models/` 创建新的模型文件 +3. **添加服务**:在 `src/your_app/services/` 创建业务逻辑 +4. **添加工具**:在 `src/your_app/utils/` 创建工具函数 + +### 数据库迁移 + +```bash +# 创建迁移 +flask db migrate -m "描述信息" + +# 应用迁移 +flask db upgrade + +# 回滚迁移 +flask db downgrade +``` + +### 运行测试 + +```bash +# 安装测试依赖 +pip install -r requirements/test.txt + +# 运行所有测试 +pytest + +# 运行特定测试文件 +pytest tests/test_example.py + +# 生成覆盖率报告 +pytest --cov=src tests/ +``` + +## 依赖管理 + +依赖按用途分类管理: + +- **base.txt**: 项目运行必需的基础依赖 +- **development.txt**: 开发工具(调试器、代码检查等) +- **production.txt**: 生产环境依赖(WSGI服务器等) +- **test.txt**: 测试框架和工具 + +安装方式: + +```bash +# 开发环境 +pip install -r requirements/base.txt +pip install -r requirements/development.txt + +# 生产环境 +pip install -r requirements/base.txt +pip install -r requirements/production.txt +``` + +## 环境变量说明 + +所有配置通过环境变量管理,详见 `.env.example` 文件。 + +**必需的环境变量:** +- `SECRET_KEY`: Flask密钥 +- `DATABASE_URL`: 数据库连接URL +- `FLASK_ENV`: 运行环境 + +## 部署 + +### 开发环境 + +```bash +python run_dev.py +``` + +### 生产环境 + +```bash +# 使用Gunicorn +gunicorn -c gunicorn.conf.py "src.your_app:create_app()" + +# 或使用uWSGI +uwsgi --ini uwsgi.ini +``` + +## 贡献指南 + +1. Fork本项目 +2. 创建功能分支 +3. 提交更改 +4. 推送到分支 +5. 创建Pull Request + +## 许可证 + +MIT License + +## 更新日志 + +### v1.0.0 (2025-01-XX) +- 初始版本 +- 基础项目结构 +- 多环境配置支持 +- 依赖分类管理 + diff --git a/TEMPLATE_INFO.md b/TEMPLATE_INFO.md new file mode 100644 index 0000000..3d9e9ac --- /dev/null +++ b/TEMPLATE_INFO.md @@ -0,0 +1,128 @@ +# 模板项目信息 + +## 模板来源 + +本模板基于 `aitsc` 项目的最佳实践抽取而成,保留了以下核心特性: + +- ✅ 标准化的项目结构 +- ✅ 多环境配置管理 +- ✅ 依赖分类管理 +- ✅ 应用工厂模式 +- ✅ 完整的测试框架 +- ✅ 文档结构模板 + +## 文件清单 + +### 配置文件 + +- `.gitignore` - Git忽略文件配置 +- `.flake8` - flake8代码检查配置 +- `pytest.ini` - pytest测试配置 +- `env.example` - 环境变量模板 +- `gunicorn.conf.py` - Gunicorn生产服务器配置 + +### 启动脚本 + +- `run_dev.py` - 开发环境启动脚本 +- `run_production.py` - 生产环境启动脚本(测试用) + +### 配置模块 (`config/`) + +- `__init__.py` - 配置选择器 +- `base.py` - 基础配置类 +- `development.py` - 开发环境配置 +- `production.py` - 生产环境配置 +- `testing.py` - 测试环境配置 +- `local.py` - 本地环境配置 + +### 源代码 (`src/your_app/`) + +- `__init__.py` - 应用工厂 +- `app.py` - 应用入口 +- `models/` - 数据模型 + - `__init__.py` + - `example.py` - 示例模型 +- `routes/` - 路由定义 + - `__init__.py` - 主路由蓝图 +- `services/` - 业务逻辑 + - `__init__.py` +- `utils/` - 工具函数 + - `__init__.py` + - `helpers.py` - 辅助函数 +- `static/` - 静态资源目录 +- `templates/` - 模板文件 + - `base.html` - 基础模板 + - `index.html` - 首页模板 + +### 依赖管理 (`requirements/`) + +- `base.txt` - 基础依赖 +- `development.txt` - 开发依赖 +- `production.txt` - 生产依赖 +- `test.txt` - 测试依赖 + +### 测试 (`tests/`) + +- `__init__.py` +- `conftest.py` - pytest配置和fixtures +- `test_example.py` - 示例测试 + +### 文档 (`docs/`) + +- `README.md` - 文档索引 +- `api/README.md` - API文档模板 +- `development/README.md` - 开发文档模板 +- `deployment/README.md` - 部署文档模板 + +### 工具脚本 (`scripts/`) + +- `init_project.py` - 项目初始化脚本 + +### 文档文件 + +- `README.md` - 项目说明 +- `QUICK_START.md` - 快速开始指南 +- `PROJECT_STRUCTURE.md` - 项目结构说明 +- `USAGE.md` - 使用说明 +- `TEMPLATE_INFO.md` - 本文件 + +## 使用方式 + +### 方式1: 直接复制 + +```bash +cp -r template my_new_project +cd my_new_project +# 然后按照README.md的说明配置 +``` + +### 方式2: 使用初始化脚本 + +```bash +cp -r template my_new_project +cd my_new_project +python scripts/init_project.py +# 脚本会引导你完成初始化 +``` + +## 下一步 + +1. 查看 [README.md](README.md) 了解完整功能 +2. 查看 [QUICK_START.md](QUICK_START.md) 快速开始 +3. 查看 [USAGE.md](USAGE.md) 了解详细使用方法 +4. 查看 [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md) 了解项目结构 + +## 版本信息 + +- 模板版本: v1.0.0 +- 创建日期: 2025-01-XX +- 基于项目: aitsc +- Python版本要求: 3.8+ + +## 贡献 + +如果你有改进建议,欢迎: +1. 提出Issue +2. 提交Pull Request +3. 分享使用经验 + diff --git a/USAGE.md b/USAGE.md new file mode 100644 index 0000000..1b73ab0 --- /dev/null +++ b/USAGE.md @@ -0,0 +1,290 @@ +# 模板使用说明 + +## 模板特性 + +本模板基于aitsc项目的最佳实践,抽取了以下核心特性: + +### ✅ 已实现的功能 + +1. **标准化项目结构** + - 清晰的目录组织(src/、config/、tests/等) + - 模块化设计,易于扩展 + +2. **多环境配置管理** + - 支持development/production/testing/local四种环境 + - 通过环境变量自动选择配置 + - 配置继承机制,减少重复 + +3. **依赖分类管理** + - base.txt: 核心依赖 + - development.txt: 开发工具 + - production.txt: 生产服务器 + - test.txt: 测试框架 + +4. **应用工厂模式** + - 灵活的Flask应用创建方式 + - 支持测试和不同环境 + +5. **数据库迁移支持** + - 使用Flask-Migrate管理数据库版本 + - 支持多数据库(SQLite/MySQL/PostgreSQL) + +6. **环境变量管理** + - 使用python-dotenv加载.env文件 + - 提供env.example模板 + +7. **完整的测试框架** + - pytest配置 + - 测试fixtures + - 示例测试用例 + +8. **文档结构** + - API文档模板 + - 开发文档模板 + - 部署文档模板 + +9. **代码质量工具** + - flake8配置 + - pytest配置 + - 支持代码格式化(Black、isort) + +10. **生产环境支持** + - Gunicorn配置 + - 日志系统 + - 错误处理 + +## 使用流程 + +### 1. 复制模板 + +```bash +cp -r template my_new_project +cd my_new_project +``` + +### 2. 运行初始化(推荐) + +```bash +python scripts/init_project.py +``` + +脚本会自动: +- 生成SECRET_KEY +- 创建.env文件 +- 创建必要目录 +- 可选:重命名应用目录 + +### 3. 手动配置(如果未使用脚本) + +```bash +# 创建虚拟环境 +python -m venv .venv +source .venv/bin/activate # Linux/Mac +# 或 .venv\Scripts\activate # Windows + +# 安装依赖 +pip install -r requirements/base.txt +pip install -r requirements/development.txt + +# 配置环境变量 +cp env.example .env +# 编辑.env文件,至少设置SECRET_KEY和DATABASE_URL +``` + +### 4. 初始化数据库 + +```bash +flask db init +flask db migrate -m "Initial migration" +flask db upgrade +``` + +### 5. 运行项目 + +```bash +python run_dev.py +``` + +## 自定义项目 + +### 重命名应用 + +1. 重命名目录: `src/your_app` -> `src/my_app` +2. 更新导入路径: + - `run_dev.py`: `from src.your_app` -> `from src.my_app` + - `run_production.py`: 同上 + - `gunicorn.conf.py`: `"src.your_app:create_app()"` -> `"src.my_app:create_app()"` + - `tests/conftest.py`: 同上 + - 所有测试文件中的导入 + +### 添加新功能 + +#### 添加路由 + +1. 在 `src/your_app/routes/` 创建新文件,例如 `api.py`: + +```python +from flask import Blueprint, jsonify + +api_bp = Blueprint('api', __name__, url_prefix='/api/v1') + +@api_bp.route('/users') +def get_users(): + return jsonify({'users': []}) +``` + +2. 在 `src/your_app/__init__.py` 注册: + +```python +from src.your_app.routes.api import api_bp +app.register_blueprint(api_bp) +``` + +#### 添加模型 + +1. 在 `src/your_app/models/` 创建新文件,例如 `user.py`: + +```python +from datetime import datetime +from src.your_app import db + +class User(db.Model): + __tablename__ = 'users' + + 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) +``` + +2. 在 `src/your_app/models/__init__.py` 导入: + +```python +from .user import User + +__all__ = ['db', 'User'] +``` + +3. 创建迁移: + +```bash +flask db migrate -m "Add User model" +flask db upgrade +``` + +#### 添加服务 + +在 `src/your_app/services/` 创建业务逻辑: + +```python +from src.your_app.models import User, db + +class UserService: + @staticmethod + def create_user(username, email): + user = User(username=username, email=email) + db.session.add(user) + db.session.commit() + return user +``` + +## 环境配置 + +### 开发环境 + +```bash +export FLASK_ENV=development +python run_dev.py +``` + +- 启用调试模式 +- 使用开发数据库 +- 详细错误信息 + +### 生产环境 + +```bash +export FLASK_ENV=production +gunicorn -c gunicorn.conf.py "src.your_app:create_app()" +``` + +- 关闭调试模式 +- 使用生产数据库 +- 安全配置 + +### 测试环境 + +```bash +export FLASK_ENV=testing +pytest +``` + +- 使用内存数据库 +- 关闭CSRF保护 +- 快速测试 + +## 常见任务 + +### 运行测试 + +```bash +pip install -r requirements/test.txt +pytest +pytest --cov=src tests/ # 带覆盖率 +``` + +### 代码检查 + +```bash +pip install -r requirements/development.txt +flake8 src/ +pylint src/ +black src/ # 格式化 +isort src/ # 排序导入 +``` + +### 数据库操作 + +```bash +# 创建迁移 +flask db migrate -m "描述" + +# 应用迁移 +flask db upgrade + +# 回滚迁移 +flask db downgrade + +# 查看迁移历史 +flask db history +``` + +## 注意事项 + +1. **不要提交敏感信息** + - `.env` 文件已加入.gitignore + - 不要将密钥、密码等提交到代码库 + +2. **环境变量必需项** + - `SECRET_KEY`: Flask密钥(必需) + - `DATABASE_URL`: 数据库连接(必需) + - `FLASK_ENV`: 运行环境(可选,默认development) + +3. **生产环境安全** + - 必须设置强SECRET_KEY + - 必须使用非SQLite数据库 + - 必须配置CORS_ORIGINS限制 + - 必须启用HTTPS + +4. **数据库迁移** + - 始终使用Flask-Migrate管理数据库变更 + - 不要直接修改数据库结构 + - 迁移文件应该提交到代码库 + +## 获取帮助 + +- 查看 [README.md](README.md) 了解完整文档 +- 查看 [QUICK_START.md](QUICK_START.md) 快速开始 +- 查看 [PROJECT_STRUCTURE.md](PROJECT_STRUCTURE.md) 了解项目结构 +- 查看 [docs/](docs/) 目录了解详细文档 + diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e854c67 --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,43 @@ +""" +配置管理模块 +根据环境变量自动选择对应的配置类 +""" +import os +from .base import Config +from .development import DevelopmentConfig +from .production import ProductionConfig +from .testing import TestingConfig +from .local import LocalConfig + +# 配置映射字典 +config_map = { + 'development': DevelopmentConfig, + 'production': ProductionConfig, + 'testing': TestingConfig, + 'local': LocalConfig, + 'default': DevelopmentConfig +} + +def get_config(): + """ + 根据环境变量获取对应的配置类 + + 环境变量: FLASK_ENV + 可选值: development, production, testing, local + + Returns: + Config类: 对应环境的配置类 + """ + env = os.environ.get('FLASK_ENV', 'development') + return config_map.get(env, config_map['default']) + +# 导出配置类 +__all__ = [ + 'Config', + 'DevelopmentConfig', + 'ProductionConfig', + 'TestingConfig', + 'LocalConfig', + 'get_config' +] + diff --git a/config/base.py b/config/base.py new file mode 100644 index 0000000..8a7410a --- /dev/null +++ b/config/base.py @@ -0,0 +1,82 @@ +""" +基础配置类 +包含所有环境通用的配置项 +""" +import os +from datetime import timedelta + +class Config: + """ + 基础配置类 + 所有环境配置都继承此类 + """ + + # Flask基础配置 + SECRET_KEY = os.environ.get('SECRET_KEY') + if not SECRET_KEY: + raise ValueError("SECRET_KEY 环境变量未设置,请在.env文件中配置") + + # 数据库配置 + SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db' + SQLALCHEMY_TRACK_MODIFICATIONS = False + SQLALCHEMY_ENGINE_OPTIONS = { + 'pool_pre_ping': True, # 连接前检查连接是否有效 + 'pool_recycle': 300, # 连接回收时间(秒) + } + + # 跨域配置 + CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*').split(',') + + # 日志配置 + LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') + LOG_FILE = os.environ.get('LOG_FILE', 'logs/app.log') + + # 缓存配置 + CACHE_TYPE = os.environ.get('CACHE_TYPE', 'simple') + CACHE_DEFAULT_TIMEOUT = int(os.environ.get('CACHE_DEFAULT_TIMEOUT', 300)) + + # Redis缓存配置(当CACHE_TYPE=redis时使用) + REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') + + # 会话配置 + PERMANENT_SESSION_LIFETIME = timedelta( + hours=int(os.environ.get('SESSION_LIFETIME_HOURS', 24)) + ) + + # 文件上传配置 + MAX_CONTENT_LENGTH = int(os.environ.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024)) # 16MB + UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', 'uploads') + + # 安全配置 + WTF_CSRF_ENABLED = os.environ.get('WTF_CSRF_ENABLED', 'True').lower() == 'true' + WTF_CSRF_TIME_LIMIT = int(os.environ.get('WTF_CSRF_TIME_LIMIT', 3600)) + + @staticmethod + def init_app(app): + """ + 初始化应用配置 + 创建必要的目录和配置日志 + """ + # 创建必要的目录 + os.makedirs('logs', exist_ok=True) + os.makedirs('uploads', exist_ok=True) + + # 配置日志 + import logging + from logging.handlers import RotatingFileHandler + + if not app.debug and not app.testing: + file_handler = RotatingFileHandler( + Config.LOG_FILE, + maxBytes=10240000, # 10MB + backupCount=10 + ) + file_handler.setFormatter(logging.Formatter( + '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]' + )) + file_handler.setLevel(getattr(logging, Config.LOG_LEVEL)) + app.logger.addHandler(file_handler) + + app.logger.setLevel(getattr(logging, Config.LOG_LEVEL)) + app.logger.info('应用启动') + diff --git a/config/development.py b/config/development.py new file mode 100644 index 0000000..d61bc76 --- /dev/null +++ b/config/development.py @@ -0,0 +1,22 @@ +""" +开发环境配置 +""" +from .base import Config + +class DevelopmentConfig(Config): + """ + 开发环境配置 + 启用调试模式,使用开发数据库 + """ + DEBUG = True + TESTING = False + + # 开发环境可以使用SQLite + SQLALCHEMY_DATABASE_URI = Config.SQLALCHEMY_DATABASE_URI or 'sqlite:///dev.db' + + # 开发环境日志级别 + LOG_LEVEL = 'DEBUG' + + # 开发环境允许所有跨域请求 + CORS_ORIGINS = ['*'] + diff --git a/config/local.py b/config/local.py new file mode 100644 index 0000000..570cd7f --- /dev/null +++ b/config/local.py @@ -0,0 +1,15 @@ +""" +本地环境配置 +用于本地开发,可以覆盖默认配置 +""" +from .development import DevelopmentConfig + +class LocalConfig(DevelopmentConfig): + """ + 本地环境配置 + 继承开发环境配置,可以添加本地特定配置 + """ + # 本地环境可以使用本地数据库 + # 可以在这里覆盖开发环境的配置 + pass + diff --git a/config/production.py b/config/production.py new file mode 100644 index 0000000..4926d04 --- /dev/null +++ b/config/production.py @@ -0,0 +1,35 @@ +""" +生产环境配置 +""" +from .base import Config + +class ProductionConfig(Config): + """ + 生产环境配置 + 关闭调试模式,使用生产数据库 + """ + DEBUG = False + TESTING = False + + # 生产环境必须使用生产数据库 + # 从环境变量获取,如果没有设置会抛出错误 + SQLALCHEMY_DATABASE_URI = Config.SQLALCHEMY_DATABASE_URI + if not SQLALCHEMY_DATABASE_URI or SQLALCHEMY_DATABASE_URI.startswith('sqlite'): + raise ValueError("生产环境必须配置非SQLite数据库") + + # 生产环境日志级别 + LOG_LEVEL = 'INFO' + + # 生产环境限制跨域来源 + # 应该从环境变量获取,格式: https://yourdomain.com,https://www.yourdomain.com + CORS_ORIGINS = Config.CORS_ORIGINS + if CORS_ORIGINS == ['*']: + import warnings + warnings.warn("生产环境CORS_ORIGINS设置为'*'存在安全风险,请配置具体域名") + + # 生产环境安全配置 + WTF_CSRF_ENABLED = True + SESSION_COOKIE_SECURE = True # 仅HTTPS传输 + SESSION_COOKIE_HTTPONLY = True # 防止XSS + SESSION_COOKIE_SAMESITE = 'Lax' # CSRF保护 + diff --git a/config/testing.py b/config/testing.py new file mode 100644 index 0000000..1492526 --- /dev/null +++ b/config/testing.py @@ -0,0 +1,25 @@ +""" +测试环境配置 +""" +from .base import Config + +class TestingConfig(Config): + """ + 测试环境配置 + 使用内存数据库,关闭CSRF保护 + """ + DEBUG = True + TESTING = True + + # 测试环境使用内存数据库 + SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:' + + # 测试环境关闭CSRF保护 + WTF_CSRF_ENABLED = False + + # 测试环境日志级别 + LOG_LEVEL = 'DEBUG' + + # 测试环境允许所有跨域请求 + CORS_ORIGINS = ['*'] + diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..8acd11a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,25 @@ +# 项目文档 + +## 文档结构 + +- `api/` - API接口文档 +- `development/` - 开发相关文档 +- `deployment/` - 部署相关文档 + +## 文档管理规范 + +1. 所有文档必须包含: + - 目标 | 版本号 | 责任人 | 最后更新日期 + - 变更记录(含修改人、修改内容) + - 关联资源链接(代码库/任务编号) + +2. 文档更新必须: + - 更新版本号(语义化版本 v<主>.<次>.<补丁>) + - 提交变更日志(>50字说明) + +## 快速链接 + +- [API文档](./api/README.md) +- [开发文档](./development/README.md) +- [部署文档](./deployment/README.md) + diff --git a/docs/api/README.md b/docs/api/README.md new file mode 100644 index 0000000..436b21d --- /dev/null +++ b/docs/api/README.md @@ -0,0 +1,57 @@ +# API接口文档 + +## 版本信息 + +- 版本: v1.0.0 +- 最后更新: 2025-01-XX +- 维护者: 开发团队 + +## API基础信息 + +- 基础URL: `http://localhost:5000/api/v1` +- 认证方式: Bearer Token(如需要) +- 数据格式: JSON + +## 接口列表 + +### 健康检查 + +**GET** `/health` + +检查服务健康状态 + +**响应示例:** +```json +{ + "status": "healthy" +} +``` + +### 首页 + +**GET** `/` + +获取首页信息 + +**响应示例:** +```json +{ + "message": "Hello, World!", + "status": "ok" +} +``` + +## 错误码说明 + +- `200` - 成功 +- `400` - 请求参数错误 +- `401` - 未授权 +- `404` - 资源不存在 +- `500` - 服务器内部错误 + +## 变更记录 + +### v1.0.0 (2025-01-XX) +- 初始版本 +- 添加健康检查和首页接口 + diff --git a/docs/deployment/README.md b/docs/deployment/README.md new file mode 100644 index 0000000..9fe5b30 --- /dev/null +++ b/docs/deployment/README.md @@ -0,0 +1,101 @@ +# 部署文档 + +## 版本信息 + +- 版本: v1.0.0 +- 最后更新: 2025-01-XX +- 维护者: 运维团队 + +## 部署前准备 + +### 1. 环境要求 + +- Python 3.8+ +- 数据库(MySQL/PostgreSQL/SQLite) +- 反向代理(Nginx,可选) + +### 2. 安装依赖 + +```bash +# 安装生产依赖 +pip install -r requirements/base.txt +pip install -r requirements/production.txt +``` + +### 3. 配置环境变量 + +```bash +# 设置生产环境 +export FLASK_ENV=production + +# 配置必要的环境变量 +# - SECRET_KEY +# - DATABASE_URL +# - CORS_ORIGINS +``` + +## 部署方式 + +### 方式1: 使用Gunicorn + +```bash +# 使用配置文件 +gunicorn -c gunicorn.conf.py "src.your_app:create_app()" + +# 或直接指定参数 +gunicorn --bind 0.0.0.0:5000 --workers 4 "src.your_app:create_app()" +``` + +### 方式2: 使用uWSGI + +```bash +uwsgi --ini uwsgi.ini +``` + +### 方式3: 使用Docker + +```bash +# 构建镜像 +docker build -t your_app . + +# 运行容器 +docker run -d -p 5000:5000 --env-file .env your_app +``` + +## Nginx配置示例 + +```nginx +server { + listen 80; + server_name your_domain.com; + + location / { + proxy_pass http://127.0.0.1:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +## 监控和日志 + +### 日志位置 + +- 应用日志: `logs/app.log` +- Gunicorn访问日志: `logs/gunicorn_access.log` +- Gunicorn错误日志: `logs/gunicorn_error.log` + +### 监控建议 + +- 使用Supervisor管理进程 +- 配置日志轮转 +- 设置健康检查端点 + +## 变更记录 + +### v1.0.0 (2025-01-XX) +- 初始版本 +- 添加部署文档 + diff --git a/docs/development/README.md b/docs/development/README.md new file mode 100644 index 0000000..f905bb3 --- /dev/null +++ b/docs/development/README.md @@ -0,0 +1,131 @@ +# 开发文档 + +## 版本信息 + +- 版本: v1.0.0 +- 最后更新: 2025-01-XX +- 维护者: 开发团队 + +## 开发环境搭建 + +### 1. 环境要求 + +- Python 3.8+ +- pip +- 虚拟环境工具(venv) + +### 2. 安装步骤 + +```bash +# 创建虚拟环境 +python -m venv .venv + +# 激活虚拟环境 +# Windows +.venv\Scripts\activate +# Linux/Mac +source .venv/bin/activate + +# 安装依赖 +pip install -r requirements/base.txt +pip install -r requirements/development.txt +``` + +### 3. 配置环境变量 + +```bash +# 复制环境变量模板 +cp env.example .env + +# 编辑.env文件 +# 至少需要配置: +# - SECRET_KEY +# - DATABASE_URL +# - FLASK_ENV +``` + +### 4. 初始化数据库 + +```bash +# 初始化迁移 +flask db init + +# 创建初始迁移 +flask db migrate -m "Initial migration" + +# 应用迁移 +flask db upgrade +``` + +### 5. 运行项目 + +```bash +python run_dev.py +``` + +## 代码规范 + +### 代码风格 + +- 使用Black进行代码格式化 +- 使用isort进行导入排序 +- 遵循PEP 8规范 + +### 代码检查 + +```bash +# 格式化代码 +black src/ + +# 排序导入 +isort src/ + +# 检查代码 +flake8 src/ +pylint src/ +``` + +## 测试 + +### 运行测试 + +```bash +# 安装测试依赖 +pip install -r requirements/test.txt + +# 运行所有测试 +pytest + +# 运行特定测试 +pytest tests/test_example.py + +# 生成覆盖率报告 +pytest --cov=src tests/ +``` + +## 数据库迁移 + +### 创建迁移 + +```bash +flask db migrate -m "描述信息" +``` + +### 应用迁移 + +```bash +flask db upgrade +``` + +### 回滚迁移 + +```bash +flask db downgrade +``` + +## 变更记录 + +### v1.0.0 (2025-01-XX) +- 初始版本 +- 添加开发环境搭建文档 + diff --git a/env.example b/env.example new file mode 100644 index 0000000..2f28897 --- /dev/null +++ b/env.example @@ -0,0 +1,81 @@ +# ======================================== +# Python项目环境变量配置示例 +# ======================================== +# 复制此文件为 .env 并根据实际情况修改配置 +# cp env.example .env + +# ======================================== +# Flask基础配置 +# ======================================== +# Flask应用密钥(必需,用于会话加密等) +# 生成方式: python -c "import secrets; print(secrets.token_hex(32))" +SECRET_KEY=your-secret-key-here-change-this-in-production + +# 应用环境(development/production/testing/local) +FLASK_ENV=development + +# 调试模式(开发环境建议True,生产环境必须False) +FLASK_DEBUG=True + +# ======================================== +# 数据库配置 +# ======================================== +# 数据库连接URL(必需) +# MySQL示例: mysql+pymysql://username:password@localhost:3306/database_name?charset=utf8mb4 +# SQLite示例: sqlite:///app.db +# PostgreSQL示例: postgresql://username:password@localhost:5432/database_name +DATABASE_URL=sqlite:///app.db + +# ======================================== +# 跨域配置 +# ======================================== +# 允许跨域的域名,多个用逗号分隔 +# 开发环境: http://localhost:3000,http://127.0.0.1:3000 +# 生产环境: https://yourdomain.com,https://www.yourdomain.com +CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 + +# ======================================== +# 日志配置 +# ======================================== +# 日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL) +LOG_LEVEL=INFO + +# 日志文件路径 +LOG_FILE=logs/app.log + +# ======================================== +# 缓存配置 +# ======================================== +# 缓存类型(simple/redis/memcached) +CACHE_TYPE=simple + +# 缓存默认超时时间(秒) +CACHE_DEFAULT_TIMEOUT=300 + +# Redis缓存URL(当CACHE_TYPE=redis时使用) +# REDIS_URL=redis://localhost:6379/0 + +# ======================================== +# 会话配置 +# ======================================== +# 会话生命周期(小时) +SESSION_LIFETIME_HOURS=24 + +# ======================================== +# 文件上传配置 +# ======================================== +# 最大文件上传大小(字节,默认16MB) +MAX_CONTENT_LENGTH=16777216 + +# 文件上传目录 +UPLOAD_FOLDER=uploads + +# ======================================== +# 安全配置 +# ======================================== +# 是否启用CSRF保护 +WTF_CSRF_ENABLED=True + +# CSRF令牌超时时间(秒) +WTF_CSRF_TIME_LIMIT=3600 + diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 0000000..40712bf --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,39 @@ +""" +Gunicorn配置文件 +生产环境使用 +""" +import multiprocessing +import os + +# 服务器socket +bind = f"0.0.0.0:{os.environ.get('PORT', 5000)}" +backlog = 2048 + +# 工作进程 +workers = multiprocessing.cpu_count() * 2 + 1 +worker_class = 'sync' +worker_connections = 1000 +timeout = 30 +keepalive = 2 + +# 日志 +accesslog = 'logs/gunicorn_access.log' +errorlog = 'logs/gunicorn_error.log' +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 = 'your_app' + +# 服务器机制 +daemon = False +pidfile = 'gunicorn.pid' +umask = 0 +user = None +group = None +tmp_upload_dir = None + +# SSL(如果需要) +# keyfile = '/path/to/keyfile' +# certfile = '/path/to/certfile' + diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..2b26af0 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,22 @@ +[pytest] +# pytest配置文件 +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* + +# 输出选项 +addopts = + -v + --strict-markers + --tb=short + --cov=src + --cov-report=term-missing + --cov-report=html + +# 标记 +markers = + unit: 单元测试 + integration: 集成测试 + slow: 慢速测试 + diff --git a/requirements/base.txt b/requirements/base.txt new file mode 100644 index 0000000..95d7583 --- /dev/null +++ b/requirements/base.txt @@ -0,0 +1,19 @@ +# 基础依赖 - 项目运行必需 +# Flask核心框架 +flask>=2.2.0 + +# 数据库ORM +flask-sqlalchemy>=3.0.2 + +# 数据库迁移 +flask-migrate>=4.0.4 + +# 跨域支持 +flask-cors>=3.0.10 + +# 环境变量管理 +python-dotenv>=1.0.0 + +# HTTP请求库 +requests>=2.28.0 + diff --git a/requirements/development.txt b/requirements/development.txt new file mode 100644 index 0000000..93b385d --- /dev/null +++ b/requirements/development.txt @@ -0,0 +1,19 @@ +# 开发依赖 - 开发工具 +# 包含base.txt的所有依赖 +-r base.txt + +# 代码格式化 +black>=23.0.0 +isort>=5.12.0 + +# 代码检查 +flake8>=6.0.0 +pylint>=2.17.0 + +# 类型检查 +mypy>=1.0.0 + +# 调试工具 +flask-debugtoolbar>=0.13.0 +ipython>=8.12.0 + diff --git a/requirements/production.txt b/requirements/production.txt new file mode 100644 index 0000000..cd1d18f --- /dev/null +++ b/requirements/production.txt @@ -0,0 +1,16 @@ +# 生产依赖 - 生产环境运行 +# 包含base.txt的所有依赖 +-r base.txt + +# WSGI服务器 +gunicorn>=21.2.0 + +# 或使用uWSGI(二选一) +# uwsgi>=2.0.21 + +# 进程管理 +supervisor>=4.2.5 + +# 性能监控 +psutil>=5.9.0 + diff --git a/requirements/test.txt b/requirements/test.txt new file mode 100644 index 0000000..ad96866 --- /dev/null +++ b/requirements/test.txt @@ -0,0 +1,16 @@ +# 测试依赖 - 测试框架和工具 +# 包含base.txt的所有依赖 +-r base.txt + +# 测试框架 +pytest>=7.4.0 +pytest-flask>=1.2.0 +pytest-cov>=4.1.0 + +# 测试工具 +faker>=19.0.0 +freezegun>=1.2.2 + +# HTTP测试 +httpx>=0.24.0 + diff --git a/run_dev.py b/run_dev.py new file mode 100644 index 0000000..0585ce4 --- /dev/null +++ b/run_dev.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +""" +开发环境启动脚本 +""" +import os +from dotenv import load_dotenv + +# 加载环境变量 +load_dotenv() + +# 设置开发环境 +os.environ.setdefault('FLASK_ENV', 'development') + +from src.your_app import create_app + +app = create_app() + +if __name__ == '__main__': + # 开发环境配置 + app.run( + host='0.0.0.0', + port=int(os.environ.get('PORT', 5000)), + debug=True, + use_reloader=True + ) + diff --git a/run_production.py b/run_production.py new file mode 100644 index 0000000..546c694 --- /dev/null +++ b/run_production.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +""" +生产环境启动脚本 +使用Gunicorn运行 +""" +import os +from dotenv import load_dotenv + +# 加载环境变量 +load_dotenv() + +# 设置生产环境 +os.environ.setdefault('FLASK_ENV', 'production') + +from src.your_app import create_app + +app = create_app() + +if __name__ == '__main__': + # 生产环境应该使用Gunicorn或uWSGI + # 此脚本仅用于测试 + print("警告: 生产环境请使用Gunicorn运行") + print("命令: gunicorn -c gunicorn.conf.py 'src.your_app:create_app()'") + app.run( + host='0.0.0.0', + port=int(os.environ.get('PORT', 5000)), + debug=False + ) + diff --git a/scripts/init_project.py b/scripts/init_project.py new file mode 100644 index 0000000..2dfa8be --- /dev/null +++ b/scripts/init_project.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +""" +项目初始化脚本 +用于快速初始化新项目 +""" +import os +import shutil +import secrets +import sys + +def generate_secret_key(): + """生成安全的密钥""" + return secrets.token_hex(32) + +def init_project(): + """初始化项目""" + print("=" * 50) + print("Python项目初始化脚本") + print("=" * 50) + + # 获取项目名称 + project_name = input("请输入项目名称(用于替换your_app): ").strip() + if not project_name: + print("错误: 项目名称不能为空") + sys.exit(1) + + # 生成密钥 + secret_key = generate_secret_key() + print(f"\n生成的SECRET_KEY: {secret_key}") + + # 创建.env文件 + if not os.path.exists('.env'): + print("\n创建.env文件...") + shutil.copy('env.example', '.env') + + # 替换SECRET_KEY + with open('.env', 'r') as f: + content = f.read() + content = content.replace('your-secret-key-here-change-this-in-production', secret_key) + with open('.env', 'w') as f: + f.write(content) + print("✓ .env文件已创建") + else: + print("⚠ .env文件已存在,跳过创建") + + # 创建必要目录 + directories = ['logs', 'uploads', 'migrations'] + for directory in directories: + if not os.path.exists(directory): + os.makedirs(directory) + print(f"✓ 创建目录: {directory}") + + # 重命名应用目录(可选) + rename = input(f"\n是否重命名应用目录 src/your_app 为 src/{project_name}? (y/n): ").strip().lower() + if rename == 'y': + old_path = 'src/your_app' + new_path = f'src/{project_name}' + if os.path.exists(old_path) and not os.path.exists(new_path): + shutil.move(old_path, new_path) + print(f"✓ 已重命名: {old_path} -> {new_path}") + print(f"⚠ 请手动更新以下文件中的导入路径:") + print(f" - run_dev.py") + print(f" - run_production.py") + print(f" - gunicorn.conf.py") + print(f" - tests/conftest.py") + print(f" - 所有测试文件") + + print("\n" + "=" * 50) + print("初始化完成!") + print("=" * 50) + print("\n下一步:") + print("1. 编辑.env文件,配置数据库和其他设置") + print("2. 安装依赖: pip install -r requirements/base.txt -r requirements/development.txt") + print("3. 初始化数据库: flask db init && flask db migrate -m 'Initial migration' && flask db upgrade") + print("4. 运行项目: python run_dev.py") + print("\n") + +if __name__ == '__main__': + init_project() + diff --git a/src/your_app/__init__.py b/src/your_app/__init__.py new file mode 100644 index 0000000..3f6ecce --- /dev/null +++ b/src/your_app/__init__.py @@ -0,0 +1,84 @@ +""" +应用工厂模块 +使用工厂模式创建Flask应用实例 +""" +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate +from flask_cors import CORS +import os +from dotenv import load_dotenv + +# 加载环境变量 +load_dotenv() + +# 导入配置系统 +from config import get_config + +# 初始化扩展 +db = SQLAlchemy() +migrate = Migrate() + +def create_app(config_class=None): + """ + 应用工厂函数 + 创建并配置Flask应用实例 + + Args: + config_class: 配置类,如果为None则自动根据环境变量选择 + + Returns: + Flask应用实例 + """ + app = Flask(__name__, + template_folder='templates', + static_folder='static') + + # 如果没有指定配置类,使用配置系统自动选择 + if config_class is None: + config_class = get_config() + + # 加载配置 + app.config.from_object(config_class) + + # 初始化配置 + config_class.init_app(app) + + # 启用跨域支持 + CORS(app, origins=app.config.get('CORS_ORIGINS', ['*'])) + + # 初始化扩展 + db.init_app(app) + migrate.init_app(app, db) + + # 注册蓝图 + from src.your_app.routes import main_bp + app.register_blueprint(main_bp) + + # TODO: 在这里注册你的其他蓝图 + # from src.your_app.routes.api import api_bp + # app.register_blueprint(api_bp) + + # 注册错误处理 + register_error_handlers(app) + + # 记录应用启动信息 + app.logger.info(f"应用启动 - 环境: {os.environ.get('FLASK_ENV', 'development')}") + app.logger.info(f"调试模式: {app.config.get('DEBUG', False)}") + app.logger.info(f"数据库: {app.config.get('SQLALCHEMY_DATABASE_URI', 'Not set')}") + + return app + +def register_error_handlers(app): + """ + 注册错误处理函数 + """ + @app.errorhandler(404) + def not_found(error): + return {'error': 'Not found'}, 404 + + @app.errorhandler(500) + def internal_error(error): + db.session.rollback() + return {'error': 'Internal server error'}, 500 + diff --git a/src/your_app/app.py b/src/your_app/app.py new file mode 100644 index 0000000..12864ec --- /dev/null +++ b/src/your_app/app.py @@ -0,0 +1,11 @@ +""" +应用入口文件 +可以直接运行此文件启动应用 +""" +from src.your_app import create_app + +app = create_app() + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) + diff --git a/src/your_app/models/__init__.py b/src/your_app/models/__init__.py new file mode 100644 index 0000000..9d98b91 --- /dev/null +++ b/src/your_app/models/__init__.py @@ -0,0 +1,12 @@ +""" +数据模型模块 +""" +from src.your_app import db + +# 导入所有模型,确保它们被注册 +# from .user import User +# from .example import Example + +# 导出db实例,方便在其他模块使用 +__all__ = ['db'] + diff --git a/src/your_app/models/example.py b/src/your_app/models/example.py new file mode 100644 index 0000000..58cd667 --- /dev/null +++ b/src/your_app/models/example.py @@ -0,0 +1,35 @@ +""" +示例模型 +展示如何定义数据模型 +""" +from datetime import datetime +from src.your_app import db + +class Example(db.Model): + """ + 示例模型 + 可以根据实际需求修改 + """ + __tablename__ = 'examples' + + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(100), nullable=False) + description = db.Column(db.Text) + created_at = db.Column(db.DateTime, default=datetime.utcnow) + updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + + def __repr__(self): + return f'' + + def to_dict(self): + """ + 转换为字典,用于JSON序列化 + """ + return { + 'id': self.id, + 'name': self.name, + 'description': self.description, + 'created_at': self.created_at.isoformat() if self.created_at else None, + 'updated_at': self.updated_at.isoformat() if self.updated_at else None, + } + diff --git a/src/your_app/routes/__init__.py b/src/your_app/routes/__init__.py new file mode 100644 index 0000000..e8d6e65 --- /dev/null +++ b/src/your_app/routes/__init__.py @@ -0,0 +1,22 @@ +""" +路由模块 +""" +from flask import Blueprint + +# 创建主蓝图 +main_bp = Blueprint('main', __name__) + +@main_bp.route('/') +def index(): + """ + 首页路由 + """ + return {'message': 'Hello, World!', 'status': 'ok'} + +@main_bp.route('/health') +def health(): + """ + 健康检查路由 + """ + return {'status': 'healthy'} + diff --git a/src/your_app/services/__init__.py b/src/your_app/services/__init__.py new file mode 100644 index 0000000..baae1df --- /dev/null +++ b/src/your_app/services/__init__.py @@ -0,0 +1,5 @@ +""" +业务逻辑服务模块 +将业务逻辑从路由中分离出来 +""" + diff --git a/src/your_app/static/.gitkeep b/src/your_app/static/.gitkeep new file mode 100644 index 0000000..8deadb6 --- /dev/null +++ b/src/your_app/static/.gitkeep @@ -0,0 +1,2 @@ +# 静态文件目录占位符 + diff --git a/src/your_app/templates/.gitkeep b/src/your_app/templates/.gitkeep new file mode 100644 index 0000000..da1d3a8 --- /dev/null +++ b/src/your_app/templates/.gitkeep @@ -0,0 +1,2 @@ +# 模板文件目录占位符 + diff --git a/src/your_app/templates/base.html b/src/your_app/templates/base.html new file mode 100644 index 0000000..fa04435 --- /dev/null +++ b/src/your_app/templates/base.html @@ -0,0 +1,25 @@ + + + + + + {% block title %}Flask应用{% endblock %} + {% block head %}{% endblock %} + + +
+

{% block header %}欢迎{% endblock %}

+
+ +
+ {% block content %}{% endblock %} +
+ + + + {% block scripts %}{% endblock %} + + + diff --git a/src/your_app/templates/index.html b/src/your_app/templates/index.html new file mode 100644 index 0000000..2007b17 --- /dev/null +++ b/src/your_app/templates/index.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} + +{% block title %}首页{% endblock %} + +{% block content %} +
+

欢迎使用Flask应用模板

+

这是一个基础模板,你可以在此基础上构建你的应用。

+ +
+

快速链接

+ +
+
+{% endblock %} + diff --git a/src/your_app/utils/__init__.py b/src/your_app/utils/__init__.py new file mode 100644 index 0000000..5147292 --- /dev/null +++ b/src/your_app/utils/__init__.py @@ -0,0 +1,5 @@ +""" +工具函数模块 +包含各种辅助函数 +""" + diff --git a/src/your_app/utils/helpers.py b/src/your_app/utils/helpers.py new file mode 100644 index 0000000..e5e93e5 --- /dev/null +++ b/src/your_app/utils/helpers.py @@ -0,0 +1,52 @@ +""" +辅助工具函数 +""" +from datetime import datetime +from typing import Any, Dict + +def format_datetime(dt: datetime) -> str: + """ + 格式化日期时间为字符串 + + Args: + dt: datetime对象 + + Returns: + 格式化后的字符串 + """ + return dt.strftime('%Y-%m-%d %H:%M:%S') if dt else None + +def success_response(data: Any = None, message: str = 'success') -> Dict: + """ + 创建成功响应 + + Args: + data: 响应数据 + message: 响应消息 + + Returns: + 响应字典 + """ + return { + 'code': 200, + 'message': message, + 'data': data + } + +def error_response(message: str = 'error', code: int = 400) -> Dict: + """ + 创建错误响应 + + Args: + message: 错误消息 + code: 错误代码 + + Returns: + 响应字典 + """ + return { + 'code': code, + 'message': message, + 'data': None + } + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..60f0865 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +""" +测试模块 +""" + diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..1ef6273 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,34 @@ +""" +pytest配置文件 +定义测试fixtures +""" +import pytest +from src.your_app import create_app, db +from config import TestingConfig + +@pytest.fixture +def app(): + """ + 创建测试应用实例 + """ + app = create_app(TestingConfig) + + with app.app_context(): + db.create_all() + yield app + db.drop_all() + +@pytest.fixture +def client(app): + """ + 创建测试客户端 + """ + return app.test_client() + +@pytest.fixture +def runner(app): + """ + 创建CLI测试运行器 + """ + return app.test_cli_runner() + diff --git a/tests/test_example.py b/tests/test_example.py new file mode 100644 index 0000000..6ae380c --- /dev/null +++ b/tests/test_example.py @@ -0,0 +1,39 @@ +""" +示例测试文件 +展示如何编写测试 +""" +import pytest +from src.your_app import db +from src.your_app.models.example import Example + +def test_index(client): + """ + 测试首页路由 + """ + response = client.get('/') + assert response.status_code == 200 + data = response.get_json() + assert data['status'] == 'ok' + +def test_health(client): + """ + 测试健康检查路由 + """ + response = client.get('/health') + assert response.status_code == 200 + data = response.get_json() + assert data['status'] == 'healthy' + +def test_example_model(app): + """ + 测试示例模型 + """ + with app.app_context(): + example = Example(name='Test', description='Test description') + db.session.add(example) + db.session.commit() + + assert example.id is not None + assert example.name == 'Test' + assert example.description == 'Test description' +