Files
FastapiAdmin/backend/app/scripts/initialize.py
T
zhangtao 9feb08a962 feat(mcp): 重构 MCP 服务器及智能助手模块
- 新增代码生成模块路由支持
- 重构 MCP 服务器API,支持增删改查接口和分页查询
- 实现 MCP 智能对话的流式响应和 WebSocket 通信
- 优化 MCP 数据模型,支持环境变量等配置项
- 改进 MCP CRUD 层,集成权限控制和统一操作方法
- 优化异常处理,提升接口错误信息准确性
- 修正依赖导入和数据校验,增强代码健壮性
2025-09-22 00:37:10 +08:00

131 lines
4.8 KiB
Python

# -*- coding: utf-8 -*-
import json
from pathlib import Path
from typing import Dict, List
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.logger import logger
from app.core.database import AsyncSessionLocal
from app.config.setting import settings
from app.api.v1.module_system.user.model import UserModel, UserRolesModel, UserPositionsModel
from app.api.v1.module_system.role.model import RoleModel, RoleDeptsModel, RoleMenusModel
from app.api.v1.module_system.position.model import PositionModel
from app.api.v1.module_system.dept.model import DeptModel
from app.api.v1.module_system.menu.model import MenuModel
from app.api.v1.module_system.params.model import ParamsModel
from app.api.v1.module_system.dict.model import DictTypeModel, DictDataModel
class InitializeData:
"""
初始化数据库和基础数据
"""
def __init__(self) -> None:
# 按照依赖关系排序:先创建基础表,再创建关联表
self.prepare_init_models = [
# 部门表(自引用,需要先创建)
DeptModel,
# 菜单表(自引用,需要先创建)
MenuModel,
# 用户表(依赖部门和角色)
UserModel,
# 角色表(依赖菜单和部门)
RoleModel,
# 岗位表(无外键依赖)
PositionModel,
# 基础表(无外键依赖)
ParamsModel,
DictTypeModel,
DictDataModel,
# 关联表(依赖基础表)
UserPositionsModel,
UserRolesModel,
RoleDeptsModel,
RoleMenusModel,
]
async def __init_data(self, db: AsyncSession) -> None:
"""初始化基础数据"""
for model in self.prepare_init_models:
table_name = model.__tablename__
# 检查表中是否已经有数据
count_result = await db.execute(select(func.count()).select_from(model))
existing_count = count_result.scalar()
if existing_count and existing_count > 0:
logger.warning(f"跳过 {table_name} 表数据初始化(表已存在 {existing_count} 条记录)")
continue
data = await self.__get_data(table_name)
if not data:
logger.warning(f"跳过 {table_name} 表,无初始化数据")
continue
try:
# 特殊处理具有嵌套 children 数据的表
if table_name in ["system_dept", "system_menu"]:
# 获取对应的模型类
model_class = DeptModel if table_name == "system_dept" else MenuModel
objs = self.__create_objects_with_children(data, model_class)
else:
# 表为空,直接插入全部数据
objs = [model(**item) for item in data]
db.add_all(objs)
await db.flush()
logger.info(f"已向 {table_name} 表写入 {len(objs)} 条记录")
except Exception as e:
logger.error(f"初始化 {table_name} 表数据失败: {str(e)}")
raise
def __create_objects_with_children(self, data: List[Dict], model_class) -> List:
"""通用递归创建对象函数,处理嵌套的 children 数据"""
objs = []
def create_object(obj_data: Dict):
# 分离 children 数据
children_data = obj_data.pop('children', [])
# 创建当前对象
obj = model_class(**obj_data)
# 递归处理子对象
if children_data:
obj.children = [create_object(child) for child in children_data]
return obj
for item in data:
objs.append(create_object(item))
return objs
async def __get_data(self, filename: str) -> List[Dict]:
"""读取初始化数据文件"""
json_path = Path.joinpath(settings.SCRIPT_DIR, f'{filename}.json')
if not json_path.exists():
return []
try:
with open(json_path, 'r', encoding='utf-8') as f:
return json.loads(f.read())
except json.JSONDecodeError as e:
logger.error(f"解析 {json_path} 失败: {str(e)}")
raise
except Exception as e:
logger.error(f"读取 {json_path} 失败: {str(e)}")
raise
async def init_db(self) -> None:
"""
执行完整初始化流程
"""
# 使用单个会话完成所有初始化操作
async with AsyncSessionLocal() as session:
async with session.begin():
await self.__init_data(session)