mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-20 20:39:55 +00:00
refactor(代码生成): 移除驼峰命名转换并优化模板变量命名
重构代码生成模块,移除不必要的驼峰命名转换逻辑,统一使用下划线命名风格 优化模板上下文变量命名,使其更加清晰和一致 修复SQL查询参数处理和表创建逻辑 简化模型转换逻辑,直接使用Pydantic的model_validate方法 更新.gitignore文件,添加前端环境变量配置
This commit is contained in:
@@ -93,20 +93,17 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
:param search: 查询参数对象
|
||||
:return: 代码生成业务表列表信息对象
|
||||
"""
|
||||
# 构建查询条件
|
||||
query = select(GenTableModel).options(selectinload(GenTableModel.columns))
|
||||
|
||||
if search:
|
||||
# 手动构建查询条件
|
||||
if search.table_name and search.table_name[1]: # ('like', value)
|
||||
query = query.where(GenTableModel.table_name.like(f"%{search.table_name[1]}%"))
|
||||
if search.table_comment and search.table_comment[1]: # ('like', value)
|
||||
query = query.where(GenTableModel.table_comment.like(f"%{search.table_comment[1]}%"))
|
||||
|
||||
query = query.order_by(GenTableModel.created_at.desc()).distinct()
|
||||
|
||||
# 获取所有数据
|
||||
result = await self.db.execute(query)
|
||||
result = await self.db.execute(
|
||||
select(GenTableModel)
|
||||
.options(selectinload(GenTableModel.columns))
|
||||
.where(
|
||||
GenTableModel.table_name.like(f"%{search.table_name}%") if search and search.table_name else GenTableModel.id.isnot(None),
|
||||
GenTableModel.table_comment.like(f"%{search.table_comment}%") if search and search.table_comment else GenTableModel.id.isnot(None),
|
||||
)
|
||||
.order_by(GenTableModel.created_at.desc())
|
||||
.distinct()
|
||||
)
|
||||
gen_table_all = result.scalars().all()
|
||||
|
||||
return gen_table_all
|
||||
@@ -141,7 +138,8 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
删除
|
||||
"""
|
||||
await self.db.execute(
|
||||
delete(GenTableModel).where(GenTableModel.id.in_(ids))
|
||||
delete(GenTableModel)
|
||||
.where(GenTableModel.id.in_(ids))
|
||||
)
|
||||
await self.db.flush()
|
||||
|
||||
@@ -189,7 +187,7 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
else:
|
||||
query_sql = (
|
||||
select(
|
||||
text("'' as database_name"), # SQLite没有数据库名概念,设为空字符串
|
||||
text("'fastapiadmin' as database_name"), # SQLite没有数据库名概念,设为空字符串
|
||||
text("name as table_name"),
|
||||
text("type as table_type"),
|
||||
text("name as table_comment"), # SQLite中使用name作为表名和注释
|
||||
@@ -204,7 +202,7 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
|
||||
# 动态条件构造
|
||||
params = {}
|
||||
if search and search.table_name and search.table_name[1]:
|
||||
if search and search.table_name:
|
||||
if settings.DATABASE_TYPE == "sqlite":
|
||||
query_sql = query_sql.where(
|
||||
text("lower(name) like lower(:table_name)")
|
||||
@@ -213,8 +211,8 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
query_sql = query_sql.where(
|
||||
text("lower(table_name) like lower(:table_name)")
|
||||
)
|
||||
params['table_name'] = f"%{search.table_name[1]}%"
|
||||
if search and search.table_comment and search.table_comment[1]:
|
||||
params['table_name'] = f"%{search.table_name}%"
|
||||
if search and search.table_comment:
|
||||
if settings.DATABASE_TYPE == "sqlite":
|
||||
query_sql = query_sql.where(
|
||||
text("lower(name) like lower(:table_comment)")
|
||||
@@ -223,7 +221,7 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
query_sql = query_sql.where(
|
||||
text("lower(table_comment) like lower(:table_comment)")
|
||||
)
|
||||
params['table_comment'] = f"%{search.table_comment[1]}%"
|
||||
params['table_comment'] = f"%{search.table_comment}%"
|
||||
|
||||
# 执行查询并绑定参数
|
||||
all_data = (await self.db.execute(query_sql, params)).fetchall()
|
||||
@@ -284,7 +282,7 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
else:
|
||||
query_sql = (
|
||||
select(
|
||||
text("'' as database_name"), # SQLite没有数据库名概念,设为空字符串
|
||||
text("'fastapiadmin' as database_name"), # SQLite没有数据库名概念,设为空字符串
|
||||
text("name as table_name"),
|
||||
text("type as table_type"),
|
||||
text("name as table_comment"), # SQLite中使用name作为表名和注释
|
||||
@@ -297,11 +295,11 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
)
|
||||
)
|
||||
|
||||
table_names_str = "','".join(table_names)
|
||||
# 修复SQL查询中的参数绑定问题
|
||||
if table_names:
|
||||
if settings.DATABASE_TYPE == "sqlite":
|
||||
# 对于SQLite,我们直接在SQL中使用表名,因为参数绑定有问题
|
||||
table_names_str = "','".join(table_names)
|
||||
query_sql = query_sql.where(
|
||||
text(f"name IN ('{table_names_str}')")
|
||||
)
|
||||
@@ -309,7 +307,7 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
else:
|
||||
# MySQL和PostgreSQL使用:table_names占位符
|
||||
query_sql = query_sql.where(
|
||||
text("table_name IN :table_names")
|
||||
text(f"table_name IN ('{table_names_str}')")
|
||||
)
|
||||
# 使用params方法正确绑定参数
|
||||
query_sql = query_sql.params(table_names=tuple(table_names))
|
||||
@@ -330,25 +328,25 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
|
||||
dict_data.append(dict_row)
|
||||
return dict_data
|
||||
|
||||
async def create_table_by_sql(self, sql_statements: List[Expression | None]) -> None:
|
||||
async def create_table_by_sql(self, sql: str) -> bool:
|
||||
"""
|
||||
根据sql语句创建表结构
|
||||
|
||||
:param db: orm对象
|
||||
:param sql_statements: sql语句的ast列表
|
||||
:param sql: sql语句
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
for sql_statement in sql_statements:
|
||||
# 检查sql_statement是否为空
|
||||
if not sql_statement:
|
||||
continue
|
||||
sql = sql_statement.sql(dialect=settings.DATABASE_TYPE)
|
||||
await self.db.execute(text(sql))
|
||||
await self.db.execute(text(sql))
|
||||
# 提交事务
|
||||
await self.db.commit()
|
||||
await self.db.flush()
|
||||
return True
|
||||
except Exception as e:
|
||||
# 如果发生异常,回滚事务
|
||||
await self.db.rollback()
|
||||
logger.error(f"创建表时发生错误: {e}")
|
||||
return False
|
||||
|
||||
|
||||
class GenTableColumnCRUD(CRUDBase[GenTableColumnModel, GenTableColumnSchema, GenTableColumnSchema]):
|
||||
@@ -358,10 +356,18 @@ class GenTableColumnCRUD(CRUDBase[GenTableColumnModel, GenTableColumnSchema, Gen
|
||||
"""初始化CRUD"""
|
||||
super().__init__(model=GenTableColumnModel, auth=auth)
|
||||
|
||||
async def get_gen_table_column_by_id(self, id: int) -> Optional[GenTableColumnModel]:
|
||||
"""根据业务表字段ID获取业务表字段信息"""
|
||||
return await self.get(id=id)
|
||||
|
||||
async def get_gen_table_column_list_by_table_id(self, table_id: int) -> Optional[GenTableColumnModel]:
|
||||
"""根据业务表ID获取业务表字段列表信息"""
|
||||
return await self.get(table_id=table_id)
|
||||
|
||||
async def list_gen_table_column_crud_by_table_id(self, table_id: int, order_by: Optional[List[Dict[str, str]]] = None) -> Sequence[GenTableColumnModel]:
|
||||
"""根据业务表ID查询业务表字段列表"""
|
||||
return await self.list(search={"table_id": table_id}, order_by=order_by)
|
||||
|
||||
async def get_gen_db_table_columns_by_name(self, table_name: str | None) -> List[GenTableColumnOutSchema]:
|
||||
"""
|
||||
根据业务表名称获取业务表字段列表信息
|
||||
@@ -421,28 +427,23 @@ class GenTableColumnCRUD(CRUDBase[GenTableColumnModel, GenTableColumnSchema, Gen
|
||||
FROM
|
||||
pragma_table_info(:table_name)
|
||||
"""
|
||||
|
||||
|
||||
query = text(query_sql).bindparams(table_name=table_name)
|
||||
gen_db_table_columns_raw = (
|
||||
rows = (
|
||||
await self.db.execute(query)
|
||||
).fetchall()
|
||||
|
||||
result = []
|
||||
for row in gen_db_table_columns_raw:
|
||||
# 构造字段信息字典
|
||||
column_dict = {
|
||||
"column_name": row[0],
|
||||
"is_required": row[1],
|
||||
"is_pk": row[2],
|
||||
"sort": row[3],
|
||||
"column_comment": row[4],
|
||||
"is_increment": row[5],
|
||||
"column_type": row[6]
|
||||
}
|
||||
|
||||
# 创建GenTableColumnOutSchema对象
|
||||
column_schema = GenTableColumnOutSchema(**column_dict)
|
||||
result.append(column_schema)
|
||||
result = [
|
||||
GenTableColumnOutSchema(
|
||||
column_name=row[0],
|
||||
is_required=row[1],
|
||||
is_pk=row[2],
|
||||
sort=row[3],
|
||||
column_comment=row[4],
|
||||
is_increment=row[5],
|
||||
column_type=row[6]
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ class GenTableQueryParam:
|
||||
table_comment: Optional[str] = Query(None, description="表注释"),
|
||||
) -> None:
|
||||
# 模糊查询字段
|
||||
self.table_name = ("like", table_name)
|
||||
self.table_comment = ("like", table_comment)
|
||||
self.table_name = table_name
|
||||
self.table_comment = table_comment
|
||||
|
||||
|
||||
class GenTableColumnQueryParam:
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
from typing import List, Literal, Optional
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
from app.common.constant import GenConstant
|
||||
from app.core.base_schema import BaseSchema
|
||||
|
||||
|
||||
class GenTableOptionModel(BaseModel):
|
||||
class GenTableOptionSchema(BaseModel):
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@@ -52,7 +51,7 @@ class GenTableBaseSchema(BaseModel):
|
||||
options: Optional[str] = Field(default=None, description='其它生成选项')
|
||||
description: Optional[str] = Field(default=None, description='功能描述')
|
||||
|
||||
params: Optional[GenTableOptionModel] = Field(default=None, description='前端传递过来的表附加信息,转换成json字符串后放到options')
|
||||
params: Optional[GenTableOptionSchema] = Field(default=None, description='前端传递过来的表附加信息,转换成json字符串后放到options')
|
||||
|
||||
|
||||
class GenTableSchema(GenTableBaseSchema):
|
||||
@@ -112,14 +111,14 @@ class GenTableColumnSchema(BaseModel):
|
||||
"""
|
||||
代码生成业务表字段创建模型
|
||||
"""
|
||||
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
table_id: Optional[int] = Field(default=None, description='归属表编号')
|
||||
column_name: Optional[str] = Field(default=None, description='列名称')
|
||||
column_comment: Optional[str] = Field(default=None, description='列描述')
|
||||
column_type: Optional[str] = Field(default=None, description='列类型')
|
||||
python_type: Optional[str] = Field(default=None, description='PYTHON类型')
|
||||
python_field: Optional[str] = Field(default=None, description='PYTHON字段名')
|
||||
python_type: Optional[str] = Field(default=None, description='python类型')
|
||||
python_field: Optional[str] = Field(default=None, description='python字段名')
|
||||
is_pk: Optional[str] = Field(default=None, description='是否主键(1是)')
|
||||
is_increment: Optional[str] = Field(default=None, description='是否自增(1是)')
|
||||
is_required: Optional[str] = Field(default=None, description='是否必填(1是)')
|
||||
|
||||
@@ -8,15 +8,15 @@ from typing import Any, List, Dict, Literal, Optional
|
||||
from sqlglot.expressions import Add, Alter, Create, Delete, Drop, Expression, Insert, Table, TruncateTable, Update
|
||||
from sqlglot import parse as sqlglot_parse
|
||||
|
||||
from app.api.v1.module_generator.gencode.model import GenTableModel
|
||||
from app.config.setting import settings
|
||||
from app.core.exceptions import CustomException
|
||||
from app.common.constant import GenConstant
|
||||
from app.common.response import SuccessResponse
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.utils.common_util import CamelCaseUtil
|
||||
from app.utils.gen_util import GenUtils
|
||||
from app.utils.jinja2_template_util import Jinja2TemplateInitializerUtil, Jinja2TemplateUtil
|
||||
from .schema import GenTableSchema, GenTableOutSchema, GenTableOutSchema, GenTableColumnSchema, GenTableColumnOutSchema, GenTableColumnDeleteSchema
|
||||
from .schema import GenTableOptionSchema, GenTableSchema, GenTableOutSchema, GenTableOutSchema, GenTableColumnSchema, GenTableColumnOutSchema, GenTableColumnDeleteSchema
|
||||
from .param import GenTableQueryParam
|
||||
from .crud import GenTableColumnCRUD, GenTableCRUD
|
||||
|
||||
@@ -34,6 +34,10 @@ class GenTableService:
|
||||
gen_table = await cls.get_gen_table_by_id_service(auth, table_id)
|
||||
gen_tables = await cls.get_gen_table_all_service(auth)
|
||||
gen_columns = await GenTableColumnService.get_gen_table_column_list_by_table_id_service(auth, table_id)
|
||||
if gen_table.options:
|
||||
table_options = GenTableOptionSchema(**json.loads(gen_table.options))
|
||||
gen_table.parent_menu_id = table_options.parent_menu_id
|
||||
gen_table.columns = gen_columns
|
||||
return dict(info=gen_table, rows=gen_columns, tables=gen_tables)
|
||||
|
||||
@classmethod
|
||||
@@ -55,23 +59,17 @@ class GenTableService:
|
||||
async def get_gen_db_table_list_by_name_service(cls, auth: AuthSchema, table_names: List[str]) -> List[GenTableOutSchema]:
|
||||
"""根据表名称组获取数据库列表信息"""
|
||||
gen_db_table_list_result = await GenTableCRUD(auth=auth).get_db_table_list_by_names(table_names)
|
||||
# 修复:将GenDBTableSchema对象转换为字典后再传递给GenTableOutSchema
|
||||
result = []
|
||||
for gen_table in CamelCaseUtil.transform_result(gen_db_table_list_result):
|
||||
# 确保gen_table是字典类型
|
||||
if hasattr(gen_table, 'model_dump'):
|
||||
gen_table_dict = gen_table.model_dump()
|
||||
elif isinstance(gen_table, dict):
|
||||
gen_table_dict = gen_table
|
||||
else:
|
||||
gen_table_dict = gen_table.__dict__
|
||||
result.append(GenTableOutSchema(**gen_table_dict))
|
||||
|
||||
# 检查是否有未找到的表
|
||||
found_table_names = [table.table_name for table in result]
|
||||
found_table_names = [table.table_name for table in gen_db_table_list_result]
|
||||
missing_tables = [name for name in table_names if name not in found_table_names]
|
||||
if missing_tables:
|
||||
raise CustomException(msg=f"以下数据表不存在: {', '.join(missing_tables)}")
|
||||
|
||||
# 修复:将GenDBTableSchema对象转换为字典后再传递给GenTableOutSchema
|
||||
result = []
|
||||
for gen_table in gen_db_table_list_result:
|
||||
result.append(GenTableOutSchema(**gen_table.model_dump()))
|
||||
|
||||
return result
|
||||
|
||||
@@ -141,7 +139,7 @@ class GenTableService:
|
||||
raise CustomException(msg='sql语句不是合法的建表语句')
|
||||
table_names = cls.__get_table_names(sql_statements)
|
||||
# 执行SQL语句创建表
|
||||
await GenTableCRUD(auth=auth).create_table_by_sql(sql_statements)
|
||||
await GenTableCRUD(auth=auth).create_table_by_sql(sql)
|
||||
gen_table_list = await cls.get_gen_db_table_list_by_name_service(auth, table_names)
|
||||
import_result = await cls.import_gen_table_service(auth, gen_table_list)
|
||||
return import_result
|
||||
@@ -261,7 +259,8 @@ class GenTableService:
|
||||
async def get_gen_table_all_service(cls, auth: AuthSchema) -> List[GenTableOutSchema]:
|
||||
"""获取所有业务表信息"""
|
||||
gen_table_all = await GenTableCRUD(auth=auth).get_gen_table_all()
|
||||
result = [GenTableOutSchema(**gen_table) for gen_table in CamelCaseUtil.transform_result(gen_table_all)]
|
||||
gen_table_all_dict = [GenTableOutSchema.model_validate(gen_table).model_dump() for gen_table in gen_table_all]
|
||||
result = [GenTableOutSchema(**gen_table) for gen_table in gen_table_all_dict]
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
@@ -273,8 +272,8 @@ class GenTableService:
|
||||
:param table_id: 业务表id
|
||||
:return: 预览数据列表
|
||||
"""
|
||||
gen_table = GenTableOutSchema(
|
||||
**CamelCaseUtil.transform_result(await GenTableCRUD(auth).get_gen_table_by_id(table_id))
|
||||
gen_table = GenTableOutSchema.model_validate(
|
||||
await GenTableCRUD(auth).get_gen_table_by_id(table_id)
|
||||
)
|
||||
await cls.set_sub_table(auth, gen_table)
|
||||
await cls.set_pk_column(gen_table)
|
||||
@@ -335,7 +334,7 @@ class GenTableService:
|
||||
async def sync_db_service(cls, auth: AuthSchema, table_name: str) -> None:
|
||||
"""同步数据库"""
|
||||
gen_table = await GenTableCRUD(auth).get_gen_table_by_name(table_name)
|
||||
table = GenTableSchema(**CamelCaseUtil.transform_result(gen_table))
|
||||
table = GenTableSchema.model_validate(gen_table)
|
||||
# 处理table.columns为None的情况
|
||||
table_columns = table.columns or []
|
||||
table_column_map = {column.column_name: column for column in table_columns}
|
||||
@@ -388,7 +387,8 @@ class GenTableService:
|
||||
gen_table_dao = GenTableCRUD(auth=auth)
|
||||
sub_table = await gen_table_dao.get_gen_table_by_name(gen_table.sub_table_name)
|
||||
if sub_table:
|
||||
gen_table.sub_table = GenTableOutSchema(**CamelCaseUtil.transform_result(sub_table))
|
||||
gen_table.sub_table = GenTableOutSchema.model_validate(sub_table)
|
||||
|
||||
|
||||
@classmethod
|
||||
async def set_pk_column(cls, gen_table: GenTableOutSchema) -> None:
|
||||
@@ -471,11 +471,11 @@ class GenTableService:
|
||||
raise CustomException(msg=f"业务表 {table_name} 不存在")
|
||||
|
||||
# 确保CamelCaseUtil.transform_result返回的是字典
|
||||
transformed_result = CamelCaseUtil.transform_result(gen_table)
|
||||
transformed_result = gen_table
|
||||
if transformed_result is None:
|
||||
raise CustomException(msg=f"业务表 {table_name} 数据转换失败")
|
||||
|
||||
gen_table_schema = GenTableOutSchema(**transformed_result)
|
||||
gen_table_schema = GenTableOutSchema.model_validate(transformed_result)
|
||||
await cls.set_sub_table(auth, gen_table_schema)
|
||||
await cls.set_pk_column(gen_table_schema)
|
||||
context = Jinja2TemplateUtil.prepare_context(gen_table_schema)
|
||||
@@ -518,6 +518,6 @@ class GenTableColumnService:
|
||||
"""获取业务表字段列表信息"""
|
||||
gen_table_column_list_result = await GenTableColumnCRUD(auth).list_gen_table_column_crud({"table_id": table_id})
|
||||
return [
|
||||
GenTableColumnOutSchema(**gen_table_column)
|
||||
for gen_table_column in CamelCaseUtil.transform_result(gen_table_column_list_result)
|
||||
GenTableColumnOutSchema.model_validate(gen_table_column)
|
||||
for gen_table_column in gen_table_column_list_result
|
||||
]
|
||||
Reference in New Issue
Block a user