mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-22 13:05:18 +00:00
- 将前端API路径从`system`和`monitor`重命名为`module_system`和`module_monitor` - 移除MongoDB相关配置和依赖 - 统一数据库类型命名为`mysql`和`postgres` - 修复代码生成模板中的字段命名问题 - 更新依赖项并移除不必要的包 - 优化数据库连接配置 - 添加新的文档和Redoc视图组件 - 修复SQL脚本中的字段注释
227 lines
8.1 KiB
Python
227 lines
8.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import re
|
|
from typing import List
|
|
|
|
from app.common.constant import GenConstant
|
|
from app.utils.string_util import StringUtil
|
|
from app.api.v1.module_generator.gencode.schema import GenTableOutSchema, GenTableSchema, GenTableColumnSchema
|
|
|
|
|
|
class GenUtils:
|
|
"""代码生成器工具类"""
|
|
|
|
@classmethod
|
|
def init_table(cls, gen_table: GenTableSchema) -> None:
|
|
"""
|
|
初始化表信息
|
|
|
|
参数:
|
|
- gen_table (GenTableSchema): 业务表对象。
|
|
|
|
返回:
|
|
- None
|
|
"""
|
|
# 只有当字段为None时才设置默认值
|
|
gen_table.class_name = cls.convert_class_name(gen_table.table_name or "")
|
|
gen_table.package_name = 'module_gencode'
|
|
gen_table.module_name = gen_table.package_name.split('.')[-1]
|
|
gen_table.business_name = gen_table.table_name.split('_')[-1]
|
|
gen_table.function_name = re.sub(r'(?:表|测试)', '', gen_table.table_comment or "")
|
|
|
|
@classmethod
|
|
def init_column_field(cls, column: GenTableColumnSchema, table: GenTableOutSchema) -> None:
|
|
"""
|
|
初始化列属性字段
|
|
|
|
参数:
|
|
- column (GenTableColumnSchema): 业务表字段对象。
|
|
- table (GenTableOutSchema): 业务表对象。
|
|
|
|
返回:
|
|
- None
|
|
"""
|
|
data_type = cls.get_db_type(column.column_type or "")
|
|
column_name = column.column_name or ""
|
|
if not table.id:
|
|
raise ValueError("业务表ID不能为空")
|
|
column.table_id = table.id
|
|
column.python_field = cls.to_camel_case(column_name)
|
|
# 只有当python_type为None时才设置默认类型
|
|
column.python_type = StringUtil.get_mapping_value_by_key_ignore_case(GenConstant.DB_TO_PYTHON, data_type)
|
|
|
|
if column.column_length is None:
|
|
column.column_length = ''
|
|
|
|
if column.column_default is None:
|
|
column.column_default = ''
|
|
|
|
if column.html_type is None:
|
|
if cls.arrays_contains(GenConstant.COLUMNTYPE_STR, data_type) or cls.arrays_contains(
|
|
GenConstant.COLUMNTYPE_TEXT, data_type
|
|
):
|
|
# 字符串长度超过500设置为文本域
|
|
column_length = cls.get_column_length(column.column_type or "")
|
|
html_type = (
|
|
GenConstant.HTML_TEXTAREA
|
|
if column_length >= 500 or cls.arrays_contains(GenConstant.COLUMNTYPE_TEXT, data_type)
|
|
else GenConstant.HTML_INPUT
|
|
)
|
|
column.html_type = html_type
|
|
elif cls.arrays_contains(GenConstant.COLUMNTYPE_TIME, data_type):
|
|
column.html_type = GenConstant.HTML_DATETIME
|
|
elif cls.arrays_contains(GenConstant.COLUMNTYPE_NUMBER, data_type):
|
|
column.html_type = GenConstant.HTML_INPUT
|
|
elif column_name.lower().endswith("status"):
|
|
column.html_type = GenConstant.HTML_RADIO
|
|
elif column_name.lower().endswith("type") or column_name.lower().endswith("sex"):
|
|
column.html_type = GenConstant.HTML_SELECT
|
|
elif column_name.lower().endswith("image"):
|
|
column.html_type = GenConstant.HTML_IMAGE_UPLOAD
|
|
elif column_name.lower().endswith("file"):
|
|
column.html_type = GenConstant.HTML_FILE_UPLOAD
|
|
elif column_name.lower().endswith("content"):
|
|
column.html_type = GenConstant.HTML_EDITOR
|
|
else:
|
|
column.html_type = GenConstant.HTML_INPUT
|
|
|
|
# 只有当is_insert为None时才设置插入字段(默认所有字段都需要插入)
|
|
if column.is_insert:
|
|
column.is_insert = GenConstant.REQUIRE
|
|
else:
|
|
column.is_insert = False
|
|
|
|
# 只有当is_edit为None时才设置编辑字段
|
|
if not cls.arrays_contains(GenConstant.COLUMNNAME_NOT_EDIT, column_name) and not column.is_pk:
|
|
column.is_edit = GenConstant.REQUIRE
|
|
else:
|
|
column.is_edit = False
|
|
|
|
# 只有当is_list为None时才设置列表字段
|
|
if not cls.arrays_contains(GenConstant.COLUMNNAME_NOT_LIST, column_name) and not column.is_pk:
|
|
column.is_list = GenConstant.REQUIRE
|
|
else:
|
|
column.is_list = False
|
|
|
|
# 只有当is_query为None时才设置查询字段
|
|
if not cls.arrays_contains(GenConstant.COLUMNNAME_NOT_QUERY, column_name) and not column.is_pk:
|
|
column.is_query = GenConstant.REQUIRE
|
|
# 直接设置查询类型,因为我们已经确定这是一个查询字段
|
|
if column_name.lower().endswith('name') or data_type in ['varchar', 'char', 'text']:
|
|
column.query_type = GenConstant.QUERY_LIKE
|
|
else:
|
|
column.query_type = GenConstant.QUERY_EQ
|
|
else:
|
|
column.is_query = False
|
|
column.query_type = None
|
|
|
|
@classmethod
|
|
def arrays_contains(cls, arr, target_value) -> bool:
|
|
"""
|
|
检查目标值是否在数组中
|
|
|
|
注意:从根本上解决问题,现在确保传入的参数都是正确的类型:
|
|
- arr 是列表类型,且在GenConstant中定义
|
|
- target_value 不会是None
|
|
|
|
参数:
|
|
- arr: 数组类型
|
|
- target_value: 目标值
|
|
|
|
返回:
|
|
- bool: 如果目标值在数组中,返回True;否则返回False
|
|
"""
|
|
# 从根本上解决问题,不再需要复杂的防御性检查
|
|
# 因为现在我们确保传入的arr是GenConstant中定义的列表常量
|
|
# 并且target_value在调用前已经被处理过不会是None
|
|
|
|
# 简单直接地执行包含检查
|
|
target_str = str(target_value).lower()
|
|
return any(str(item).lower() == target_str for item in arr)
|
|
|
|
@classmethod
|
|
def convert_class_name(cls, table_name: str) -> str:
|
|
"""
|
|
表名转换成 Python 类名
|
|
|
|
参数:
|
|
- table_name (str): 业务表名。
|
|
|
|
返回:
|
|
- str: Python 类名。
|
|
"""
|
|
return StringUtil.convert_to_camel_case(table_name)
|
|
|
|
@classmethod
|
|
def replace_first(cls, input_string: str, search_list: List[str]) -> str:
|
|
"""
|
|
批量替换前缀
|
|
|
|
参数:
|
|
- input_string (str): 需要被替换的字符串。
|
|
- search_list (List[str]): 可替换的字符串列表。
|
|
|
|
返回:
|
|
- str: 替换后的字符串。
|
|
"""
|
|
for search_string in search_list:
|
|
if input_string.startswith(search_string):
|
|
return input_string.replace(search_string, '', 1)
|
|
return input_string
|
|
|
|
@classmethod
|
|
def get_db_type(cls, column_type: str) -> str:
|
|
"""
|
|
获取数据库类型字段
|
|
|
|
参数:
|
|
- column_type (str): 字段类型。
|
|
|
|
返回:
|
|
- str: 数据库类型。
|
|
"""
|
|
if '(' in column_type:
|
|
return column_type.split('(')[0]
|
|
return column_type
|
|
|
|
@classmethod
|
|
def get_column_length(cls, column_type: str) -> int:
|
|
"""
|
|
获取字段长度
|
|
|
|
参数:
|
|
- column_type (str): 字段类型,例如 'varchar(255)' 或 'decimal(10,2)'
|
|
|
|
返回:
|
|
- int: 字段长度(优先取第一个长度值,无法解析时返回0)。
|
|
"""
|
|
if '(' in column_type:
|
|
length = len(column_type.split('(')[1].split(')')[0])
|
|
return length
|
|
return 0
|
|
|
|
@classmethod
|
|
def split_column_type(cls, column_type: str) -> List[str]:
|
|
"""
|
|
拆分列类型
|
|
|
|
参数:
|
|
- column_type (str): 字段类型。
|
|
|
|
返回:
|
|
- List[str]: 拆分结果。
|
|
"""
|
|
if '(' in column_type and ')' in column_type:
|
|
return column_type.split('(')[1].split(')')[0].split(',')
|
|
return []
|
|
|
|
@classmethod
|
|
def to_camel_case(cls, text: str) -> str:
|
|
"""
|
|
将字符串转换为驼峰命名
|
|
|
|
param text: 需要转换的字符串
|
|
:return: 驼峰命名
|
|
"""
|
|
parts = text.split('_')
|
|
return parts[0] + ''.join(word.capitalize() for word in parts[1:]) |