refactor: P7 切尾——删除 application/extensions/utils,WSGI 切 src

【切尾】
- src/app.py:应用工厂(原 application/factory.py)
- src/extensions.py:扩展注册编排(原 extensions/)
- src/wsgi.py:生产 WSGI 入口
- 根 app.py 改为 from src.app import create_app(开发入口保留)
- gunicorn/Docker/compose 指向 src.wsgi:app
- 删除 application/、extensions/、utils/(全部代码已迁入 src/)

【清理】21 个 router 中间件导入改 src.core;修复 level 服务潜在 bug
(utils.load2dict 不存在 → model_to_dict);测试文件 R 导入改 src.core

【里程碑】全项目 flake8 从 P1 基线 154 条 → **0 条**;
12 passed;app.py 与 src.wsgi 双入口均启动

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 19:45:28 +08:00
co-authored by Claude
parent 4d74b31431
commit 5504f3f2c6
176 changed files with 272 additions and 1674 deletions
+154
View File
@@ -0,0 +1,154 @@
"""
应用工厂模块
=============================================================
负责创建和配置 Flask 应用实例。
说明:
原位于 application/factory.py,P7 切尾后迁移至 src/app.py。
依赖组合根在此注入(见 _inject_dependencies)。
"""
import os
from flask import Flask
from flask_cors import CORS
from werkzeug.middleware.proxy_fix import ProxyFix
from src.core.middleware import register_middleware, register_transaction, register_error_handlers, register_operation_log
from src.routes.v1 import register_v1
from src.extensions import register_extends
from config import DatabaseConfig, REDIS_URL
from src.common.utils.json import JSONEncoder
# 模型注册中心:确保 Flask-Migrate 全量识别表结构(见 src/models_registry.py)
import src.models_registry # noqa: F401
def create_app():
"""
创建并配置 Flask 应用实例
配置流程:
1. 创建 Flask 核心对象
2. 配置 Redis 连接
3. 加载数据库配置
4. 设置 JSON 序列化器
5. 配置跨域资源共享
6. 注册操作日志与事务拦截器
7. 注册 API v1 路由
8. 初始化第三方扩展
9. 注册中间件
10. 注入依赖(权限提供方 / 操作日志写入器)
Returns:
Flask: 配置完成的应用实例
"""
# ============================================================
# 创建 Flask 核心对象
# ============================================================
app = Flask(
__name__,
template_folder='templates',
static_folder='../static'
)
# ============================================================
# Redis 配置(用于缓存和会话存储)
# ============================================================
app.config['REDIS_URL'] = REDIS_URL
# ============================================================
# 加载数据库配置
# ============================================================
app.config.from_object(DatabaseConfig)
# ============================================================
# 自定义 JSON 序列化器(支持 datetime 等特殊类型)
# ============================================================
app.json = JSONEncoder(app)
# ============================================================
# 跨域资源共享配置
# ============================================================
from config import CORS_ALLOWED_ORIGINS
if CORS_ALLOWED_ORIGINS:
allowed_origins = [origin.strip() for origin in CORS_ALLOWED_ORIGINS.split(',') if origin.strip()]
CORS(
app,
resources={r"/*": {"origins": allowed_origins}},
supports_credentials=True
)
else:
CORS(
app,
resources={r"/*": {"origins": "*"}},
supports_credentials=False
)
# ============================================================
# 可信代理配置(反向代理环境下获取真实客户端IP)
# ============================================================
proxy_num = int(os.getenv('PROXY_NUM', 0))
if proxy_num > 0:
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=proxy_num, x_proto=proxy_num)
# ============================================================
# 注册操作日志自动记录中间件(须在事务拦截器之前)
# ============================================================
register_operation_log(app)
# ============================================================
# 注册 AOP 事务拦截器
# ============================================================
register_transaction(app)
# ============================================================
# 注册 API v1 路由(全部业务蓝图挂载 /api/v1)
# ============================================================
register_v1(app)
# ============================================================
# 初始化第三方扩展
# ============================================================
register_extends(app)
# ============================================================
# 注册中间件(请求/响应拦截处理)
# ============================================================
register_middleware(app)
# ============================================================
# 注册全局异常处理器(最后注册,捕获所有异常)
# ============================================================
register_error_handlers(app)
# ============================================================
# 依赖注入(组合根注入业务实现)
# ============================================================
_inject_dependencies(app)
return app
def _inject_dependencies(app):
"""
依赖注入:向 core 中间件注入业务实现
1. permission_provider:权限校验数据提供方(menu 服务)
2. operation_log_writer:操作日志写入器(log 服务)
"""
from src.modules.system.menu.service import get_user_permissions
from src.modules.log.service import record_operation_log
# ---- 权限提供方 ----
class MenuPermissionProvider:
"""权限数据提供方(适配 menu 服务)。"""
def get_user_permissions(self, user_id):
return get_user_permissions(user_id)
app.extensions['permission_provider'] = MenuPermissionProvider()
# ---- 操作日志写入器 ----
app.extensions['operation_log_writer'] = record_operation_log
+1 -1
View File
@@ -60,7 +60,7 @@ def get_err(form):
str: 拼接后的错误信息字符串,多个错误用 '/' 分隔
Examples:
>>> from application.forms.level import LevelForm
>>> from src.modules.system.level.schema import LevelForm
>>> form = LevelForm(request.form)
>>> if not form.validate():
... err_msg = get_err(form)
+42
View File
@@ -0,0 +1,42 @@
"""
扩展初始化编排
=============================================================
整合自原 extensions/ 包。实例定义位于 src/core/(database/redis_client/
mail/scheduler),本模块仅负责各扩展的 init_app 编排。
依赖约束:仅依赖 src.core,不依赖 modules 层。
"""
from flask_migrate import Migrate
from src.core.database import db
from src.core.redis_client import init_redis
from src.core.mail import init_mail
from src.core.scheduler import scheduler
# Flask-Migrate 实例(migrations/env.py 通过 current_app.extensions['migrate'] 使用)
migrate = Migrate()
def register_extends(app):
"""
注册并初始化所有第三方扩展。
Args:
app: Flask 应用实例
"""
# 1. SQLAlchemy 数据库
db.init_app(app)
# 2. Flask-Migrate 数据库迁移
migrate.init_app(app, db)
# 3. Redis 缓存
init_redis(app)
# 4. Flask-Mail 邮件
init_mail(app)
# 5. APScheduler 定时任务
scheduler.init_app(app)
+2 -2
View File
@@ -54,8 +54,8 @@
from flask import Blueprint
from application.middleware.check_permission import check_permission
from application.middleware.check_demo import check_demo
from src.core.permission import check_permission
from src.core.middleware import check_demo
from src.modules.system.role import service as role_menu
from src.common.utils.request import parse_request_body
+2 -2
View File
@@ -13,8 +13,8 @@
from flask import Blueprint
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.user import service as user_role
from src.core import response as R
user_role_blue = Blueprint('user_role', __name__, url_prefix='/user/role')
+1 -1
View File
@@ -47,7 +47,7 @@
"""
from flask import Blueprint
from sqlalchemy import and_
from application.middleware.check_demo import check_demo
from src.core.middleware import check_demo
from src.modules.auth import service as login
from src.modules.log import service as login_log
from src.modules.system.user.models import User
+2 -2
View File
@@ -57,8 +57,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.city import service as city
from src.common.utils.request import parse_request_body
+2 -2
View File
@@ -18,8 +18,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.cms.article import service as article
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -17,8 +17,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.cms.category import service as category
from src.common.utils.request import parse_request_body
+2 -2
View File
@@ -57,8 +57,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.cms.link import service as link
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -55,8 +55,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.configuration import service as config
from src.modules.configuration import service as config_item
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -55,8 +55,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.dictionary import service as dict
from src.modules.dictionary import service as dict_item
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -17,8 +17,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.file_template import service as file_template
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -7,8 +7,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.job import service as job
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -17,8 +17,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.log import service as login_log
from src.modules.log import service as operation_log
from src.common.utils.request import parse_batch_ids
+2 -2
View File
@@ -55,8 +55,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.notice import service as notice
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -59,8 +59,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.param import service as param
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -57,8 +57,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.dept import service as dept
from src.common.utils.request import parse_request_body
+2 -2
View File
@@ -58,8 +58,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.level import service as level
from src.common.utils.request import parse_batch_ids, parse_request_body
+1 -2
View File
@@ -75,7 +75,6 @@ from sqlalchemy import and_
from openpyxl.reader.excel import load_workbook
from openpyxl.workbook import Workbook
import utils
from src.common.constants.common import PAGE_SIZE
from src.modules.system.level.schema import LevelForm, LevelStatusForm
@@ -530,7 +529,7 @@ def get_level_list():
# 转换为字典列表
result = []
for level in level_list:
result.append(utils.load2dict(level))
result.append(model_to_dict(level))
return result
+2 -2
View File
@@ -55,8 +55,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.menu import service as menu
from src.common.utils.request import parse_request_body
+2 -2
View File
@@ -57,8 +57,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.position import service as position
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -57,8 +57,8 @@
"""
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.role import service as role
from src.common.utils.request import parse_batch_ids, parse_request_body
+2 -2
View File
@@ -58,8 +58,8 @@
from flask import Blueprint, request
from application.middleware.check_demo import check_demo
from application.middleware.check_permission import check_permission
from src.core.middleware import check_demo
from src.core.permission import check_permission
from src.modules.system.user import service as user
from src.common.utils.request import parse_batch_ids, parse_request_body
+5 -4
View File
@@ -52,18 +52,19 @@
from flask import Blueprint
from application.middleware.check_demo import check_demo
from src.core.middleware import check_demo
from src.modules.upload import service as upload
upload_blue = Blueprint('upload', __name__, url_prefix='/upload')
from config import UPLOAD_ALLOWED_EXTS
from src.core import response as R
upload_blue = Blueprint("upload", __name__, url_prefix="/upload")
# ============================================================
# 文件上传
# ============================================================
@upload_blue.route('/uploadFile', methods=["POST"])
@upload_blue.route("/uploadFile", methods=["POST"])
@check_demo
def upload_file():
"""
+11
View File
@@ -0,0 +1,11 @@
"""
生产 WSGI 入口
=============================================================
启动方式:
gunicorn -c gunicorn.conf.py src.wsgi:app
"""
from src.app import create_app
app = create_app()