mirror of
https://github.com/fastapi-practices/fastapi-best-architecture.git
synced 2026-09-21 21:15:13 +00:00
Optimize naming and preview in code generation (#764)
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
包含代码生成的相关配置,详情查看:`generator/model/gen_business.py`
|
||||
|
||||
### 2. 代码生成模型
|
||||
### 2. 代码生成模型列
|
||||
|
||||
包含代码生成所需要的模型列信息,就像正常定义模型列一样,目前支持的功能有限
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ from fastapi import APIRouter
|
||||
from backend.core.conf import settings
|
||||
from backend.plugin.code_generator.api.v1.business import router as business_router
|
||||
from backend.plugin.code_generator.api.v1.code import router as gen_router
|
||||
from backend.plugin.code_generator.api.v1.column import router as model_router
|
||||
from backend.plugin.code_generator.api.v1.column import router as column_router
|
||||
|
||||
v1 = APIRouter(prefix=f'{settings.FASTAPI_API_V1_PATH}/generates', tags=['代码生成'])
|
||||
|
||||
v1.include_router(business_router, prefix='/businesses')
|
||||
v1.include_router(model_router, prefix='/models')
|
||||
v1.include_router(column_router, prefix='/columns')
|
||||
v1.include_router(gen_router, prefix='/codes')
|
||||
|
||||
@@ -15,13 +15,19 @@ from backend.plugin.code_generator.schema.business import (
|
||||
GetGenBusinessDetail,
|
||||
UpdateGenBusinessParam,
|
||||
)
|
||||
from backend.plugin.code_generator.schema.column import GetGenModelDetail
|
||||
from backend.plugin.code_generator.schema.column import GetGenColumnDetail
|
||||
from backend.plugin.code_generator.service.business_service import gen_business_service
|
||||
from backend.plugin.code_generator.service.column_service import gen_model_service
|
||||
from backend.plugin.code_generator.service.column_service import gen_column_service
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/all', summary='获取所有代码生成业务', dependencies=[DependsJwtAuth])
|
||||
async def get_all_businesses() -> ResponseSchemaModel[list[GetGenBusinessDetail]]:
|
||||
data = await gen_business_service.get_all()
|
||||
return response_base.success(data=data)
|
||||
|
||||
|
||||
@router.get('/{pk}', summary='获取代码生成业务详情', dependencies=[DependsJwtAuth])
|
||||
async def get_business(
|
||||
pk: Annotated[int, Path(description='业务 ID')],
|
||||
@@ -47,11 +53,11 @@ async def get_businesses_paged(
|
||||
return response_base.success(data=page_data)
|
||||
|
||||
|
||||
@router.get('/{pk}/models', summary='获取代码生成业务所有模型', dependencies=[DependsJwtAuth])
|
||||
async def get_business_all_models(
|
||||
@router.get('/{pk}/columns', summary='获取代码生成业务所有模型列', dependencies=[DependsJwtAuth])
|
||||
async def get_business_all_columns(
|
||||
pk: Annotated[int, Path(description='业务 ID')],
|
||||
) -> ResponseSchemaModel[list[GetGenModelDetail]]:
|
||||
data = await gen_model_service.get_models(business_id=pk)
|
||||
) -> ResponseSchemaModel[list[GetGenColumnDetail]]:
|
||||
data = await gen_column_service.get_columns(business_id=pk)
|
||||
return response_base.success(data=data)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ router = APIRouter()
|
||||
@router.get('/tables', summary='获取数据库表')
|
||||
async def get_all_tables(
|
||||
table_schema: Annotated[str, Query(description='数据库名')] = 'fba',
|
||||
) -> ResponseSchemaModel[list[str]]:
|
||||
) -> ResponseSchemaModel[list[dict[str, str]]]:
|
||||
data = await gen_service.get_tables(table_schema=table_schema)
|
||||
return response_base.success(data=data)
|
||||
|
||||
|
||||
@@ -8,47 +8,47 @@ from backend.common.response.response_schema import ResponseModel, ResponseSchem
|
||||
from backend.common.security.jwt import DependsJwtAuth
|
||||
from backend.common.security.permission import RequestPermission
|
||||
from backend.common.security.rbac import DependsRBAC
|
||||
from backend.plugin.code_generator.schema.column import CreateGenModelParam, GetGenModelDetail, UpdateGenModelParam
|
||||
from backend.plugin.code_generator.service.column_service import gen_model_service
|
||||
from backend.plugin.code_generator.schema.column import CreateGenColumnParam, GetGenColumnDetail, UpdateGenColumnParam
|
||||
from backend.plugin.code_generator.service.column_service import gen_column_service
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/types', summary='获取代码生成模型列类型', dependencies=[DependsJwtAuth])
|
||||
async def get_model_types() -> ResponseSchemaModel[list[str]]:
|
||||
model_types = await gen_model_service.get_types()
|
||||
return response_base.success(data=model_types)
|
||||
async def get_column_types() -> ResponseSchemaModel[list[str]]:
|
||||
column_types = await gen_column_service.get_types()
|
||||
return response_base.success(data=column_types)
|
||||
|
||||
|
||||
@router.get('/{pk}', summary='获取代码生成模型详情', dependencies=[DependsJwtAuth])
|
||||
async def get_model(pk: Annotated[int, Path(description='模型 ID')]) -> ResponseSchemaModel[GetGenModelDetail]:
|
||||
data = await gen_model_service.get(pk=pk)
|
||||
@router.get('/{pk}', summary='获取代码生成模型列详情', dependencies=[DependsJwtAuth])
|
||||
async def get_column(pk: Annotated[int, Path(description='模型列 ID')]) -> ResponseSchemaModel[GetGenColumnDetail]:
|
||||
data = await gen_column_service.get(pk=pk)
|
||||
return response_base.success(data=data)
|
||||
|
||||
|
||||
@router.post(
|
||||
'',
|
||||
summary='创建代码生成模型',
|
||||
summary='创建代码生成模型列',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('codegen:model:add')),
|
||||
Depends(RequestPermission('codegen:column:add')),
|
||||
DependsRBAC,
|
||||
],
|
||||
)
|
||||
async def create_model(obj: CreateGenModelParam) -> ResponseModel:
|
||||
await gen_model_service.create(obj=obj)
|
||||
async def create_column(obj: CreateGenColumnParam) -> ResponseModel:
|
||||
await gen_column_service.create(obj=obj)
|
||||
return response_base.success()
|
||||
|
||||
|
||||
@router.put(
|
||||
'/{pk}',
|
||||
summary='更新代码生成模型',
|
||||
summary='更新代码生成模型列',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('codegen:model:edit')),
|
||||
Depends(RequestPermission('codegen:column:edit')),
|
||||
DependsRBAC,
|
||||
],
|
||||
)
|
||||
async def update_model(pk: Annotated[int, Path(description='模型 ID')], obj: UpdateGenModelParam) -> ResponseModel:
|
||||
count = await gen_model_service.update(pk=pk, obj=obj)
|
||||
async def update_column(pk: Annotated[int, Path(description='模型列 ID')], obj: UpdateGenColumnParam) -> ResponseModel:
|
||||
count = await gen_column_service.update(pk=pk, obj=obj)
|
||||
if count > 0:
|
||||
return response_base.success()
|
||||
return response_base.fail()
|
||||
@@ -56,14 +56,14 @@ async def update_model(pk: Annotated[int, Path(description='模型 ID')], obj: U
|
||||
|
||||
@router.delete(
|
||||
'/{pk}',
|
||||
summary='删除代码生成模型',
|
||||
summary='删除代码生成模型列',
|
||||
dependencies=[
|
||||
Depends(RequestPermission('codegen:model:del')),
|
||||
Depends(RequestPermission('codegen:column:del')),
|
||||
DependsRBAC,
|
||||
],
|
||||
)
|
||||
async def delete_model(pk: Annotated[int, Path(description='模型 ID')]) -> ResponseModel:
|
||||
count = await gen_model_service.delete(pk=pk)
|
||||
async def delete_column(pk: Annotated[int, Path(description='模型列 ID')]) -> ResponseModel:
|
||||
count = await gen_column_service.delete(pk=pk)
|
||||
if count > 0:
|
||||
return response_base.success()
|
||||
return response_base.fail()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@@ -32,6 +33,15 @@ class CRUDGenBusiness(CRUDPlus[GenBusiness]):
|
||||
"""
|
||||
return await self.select_model_by_column(db, table_name=name)
|
||||
|
||||
async def get_all(self, db: AsyncSession) -> Sequence[GenBusiness]:
|
||||
"""
|
||||
获取所有代码生成业务
|
||||
|
||||
:param db: 数据库会话
|
||||
:return:
|
||||
"""
|
||||
return await self.select_models(db)
|
||||
|
||||
async def get_list(self, table_name: str | None) -> Select:
|
||||
"""
|
||||
获取所有代码生成业务
|
||||
@@ -44,7 +54,7 @@ class CRUDGenBusiness(CRUDPlus[GenBusiness]):
|
||||
if table_name is not None:
|
||||
filters['table_name__like'] = f'%{table_name}%'
|
||||
|
||||
return await self.select_order('id', 'desc', **filters)
|
||||
return await self.select_order('id', 'desc', load_strategies={'gen_column': 'noload'}, **filters)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateGenBusinessParam) -> None:
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Row, text
|
||||
from sqlalchemy import Row, RowMapping, text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from backend.core.conf import settings
|
||||
@@ -12,7 +12,7 @@ class CRUDGen:
|
||||
"""代码生成 CRUD 类"""
|
||||
|
||||
@staticmethod
|
||||
async def get_all_tables(db: AsyncSession, table_schema: str) -> Sequence[str]:
|
||||
async def get_all_tables(db: AsyncSession, table_schema: str) -> Sequence[RowMapping]:
|
||||
"""
|
||||
获取所有表名
|
||||
|
||||
@@ -22,20 +22,23 @@ class CRUDGen:
|
||||
"""
|
||||
if settings.DATABASE_TYPE == 'mysql':
|
||||
sql = """
|
||||
SELECT table_name AS table_name FROM information_schema.tables
|
||||
WHERE table_name NOT LIKE 'sys_gen_%'
|
||||
SELECT table_name AS table_name, table_comment AS table_comment
|
||||
FROM information_schema.tables
|
||||
WHERE table_name NOT LIKE 'sys_gen_%'
|
||||
AND table_schema = :table_schema;
|
||||
"""
|
||||
else:
|
||||
sql = """
|
||||
SELECT table_name AS table_name FROM information_schema.tables
|
||||
WHERE table_name NOT LIKE 'sys_gen_%'
|
||||
AND table_catalog = :table_schema
|
||||
AND table_schema = 'public'; -- schema 通常是 'public'
|
||||
SELECT c.relname AS table_name, obj_description(c.oid) AS table_comment
|
||||
FROM pg_class c
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'r'
|
||||
AND n.nspname = 'public' -- schema 通常是 'public'
|
||||
AND c.relname NOT LIKE 'sys_gen_%';
|
||||
"""
|
||||
stmt = text(sql).bindparams(table_schema=table_schema)
|
||||
result = await db.execute(stmt)
|
||||
return result.scalars().all()
|
||||
return result.mappings().all()
|
||||
|
||||
@staticmethod
|
||||
async def get_table(db: AsyncSession, table_name: str) -> Row[tuple]:
|
||||
@@ -48,18 +51,19 @@ class CRUDGen:
|
||||
"""
|
||||
if settings.DATABASE_TYPE == 'mysql':
|
||||
sql = """
|
||||
SELECT table_name AS table_name, table_comment AS table_comment FROM information_schema.tables
|
||||
SELECT table_name AS table_name, table_comment AS table_comment
|
||||
FROM information_schema.tables
|
||||
WHERE table_name NOT LIKE 'sys_gen_%'
|
||||
AND table_name = :table_name;
|
||||
"""
|
||||
else:
|
||||
sql = """
|
||||
SELECT t.tablename AS table_name,
|
||||
pg_catalog.obj_description(t.tablename::regclass, 'pg_class') AS table_comment
|
||||
FROM pg_tables t
|
||||
WHERE t.tablename NOT LIKE 'sys_gen_%'
|
||||
AND t.tablename = :table_name
|
||||
AND t.schemaname = 'public'; -- schema 通常是 'public'
|
||||
SELECT c.relname AS table_name, obj_description(c.oid) AS table_comment
|
||||
FROM pg_class c
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relkind = 'r'
|
||||
AND n.nspname = 'public' -- schema 通常是 'public'
|
||||
AND c.relname NOT LIKE 'sys_gen_%';
|
||||
"""
|
||||
stmt = text(sql).bindparams(table_name=table_name)
|
||||
result = await db.execute(stmt)
|
||||
|
||||
@@ -6,11 +6,11 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy_crud_plus import CRUDPlus
|
||||
|
||||
from backend.plugin.code_generator.model import GenColumn
|
||||
from backend.plugin.code_generator.schema.column import CreateGenModelParam, UpdateGenModelParam
|
||||
from backend.plugin.code_generator.schema.column import CreateGenColumnParam, UpdateGenColumnParam
|
||||
|
||||
|
||||
class CRUDGenModel(CRUDPlus[GenColumn]):
|
||||
"""代码生成模型 CRUD 类"""
|
||||
class CRUDGenColumn(CRUDPlus[GenColumn]):
|
||||
"""代码生成模型列 CRUD 类"""
|
||||
|
||||
async def get(self, db: AsyncSession, pk: int) -> GenColumn | None:
|
||||
"""
|
||||
@@ -32,24 +32,24 @@ class CRUDGenModel(CRUDPlus[GenColumn]):
|
||||
"""
|
||||
return await self.select_models_order(db, sort_columns='sort', gen_business_id=business_id)
|
||||
|
||||
async def create(self, db: AsyncSession, obj: CreateGenModelParam, pd_type: str | None) -> None:
|
||||
async def create(self, db: AsyncSession, obj: CreateGenColumnParam, pd_type: str | None) -> None:
|
||||
"""
|
||||
创建代码生成模型
|
||||
创建代码生成模型列
|
||||
|
||||
:param db: 数据库会话
|
||||
:param obj: 创建代码生成模型参数
|
||||
:param obj: 创建代码生成模型列参数
|
||||
:param pd_type: Pydantic 类型
|
||||
:return:
|
||||
"""
|
||||
await self.create_model(db, obj, pd_type=pd_type)
|
||||
|
||||
async def update(self, db: AsyncSession, pk: int, obj: UpdateGenModelParam, pd_type: str | None) -> int:
|
||||
async def update(self, db: AsyncSession, pk: int, obj: UpdateGenColumnParam, pd_type: str | None) -> int:
|
||||
"""
|
||||
更新代码生成模型
|
||||
更新代码生成模型列
|
||||
|
||||
:param db: 数据库会话
|
||||
:param pk: 代码生成模型 ID
|
||||
:param obj: 更新代码生成模型参数
|
||||
:param pk: 代码生成模型列 ID
|
||||
:param obj: 更新代码生成模型列参数
|
||||
:param pd_type: Pydantic 类型
|
||||
:return:
|
||||
"""
|
||||
@@ -57,13 +57,13 @@ class CRUDGenModel(CRUDPlus[GenColumn]):
|
||||
|
||||
async def delete(self, db: AsyncSession, pk: int) -> int:
|
||||
"""
|
||||
删除代码生成模型
|
||||
删除代码生成模型列
|
||||
|
||||
:param db: 数据库会话
|
||||
:param pk: 代码生成模型 ID
|
||||
:param pk: 代码生成模型列 ID
|
||||
:return:
|
||||
"""
|
||||
return await self.delete_model(db, pk)
|
||||
|
||||
|
||||
gen_model_dao: CRUDGenModel = CRUDGenModel(GenColumn)
|
||||
gen_column_dao: CRUDGenColumn = CRUDGenColumn(GenColumn)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from backend.common.enums import StrEnum
|
||||
|
||||
|
||||
class GenModelMySQLColumnType(StrEnum):
|
||||
class GenMySQLColumnType(StrEnum):
|
||||
"""代码生成模型列类型(MySQL)"""
|
||||
|
||||
# Python 类型映射
|
||||
@@ -68,7 +68,7 @@ class GenModelMySQLColumnType(StrEnum):
|
||||
YEAR = 'int'
|
||||
|
||||
|
||||
class GenModelPostgreSQLColumnType(StrEnum):
|
||||
class GenPostgreSQLColumnType(StrEnum):
|
||||
"""代码生成模型列类型(PostgreSQL)"""
|
||||
|
||||
# Python 类型映射
|
||||
|
||||
@@ -33,5 +33,5 @@ class GenBusiness(Base):
|
||||
remark: Mapped[str | None] = mapped_column(
|
||||
LONGTEXT().with_variant(TEXT, 'postgresql'), default=None, comment='备注'
|
||||
)
|
||||
# 代码生成业务模型一对多
|
||||
# 代码生成业务模型列一对多
|
||||
gen_column: Mapped[list['GenColumn']] = relationship(init=False, back_populates='gen_business')
|
||||
|
||||
@@ -31,7 +31,7 @@ class GenColumn(DataClassBase):
|
||||
is_pk: Mapped[bool] = mapped_column(default=False, comment='是否主键')
|
||||
is_nullable: Mapped[bool] = mapped_column(default=False, comment='是否可为空')
|
||||
|
||||
# 代码生成业务模型一对多
|
||||
# 代码生成业务模型列一对多
|
||||
gen_business_id: Mapped[int] = mapped_column(
|
||||
BigInteger, ForeignKey('gen_business.id', ondelete='CASCADE'), default=0, comment='代码生成业务ID'
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[plugin]
|
||||
summary = '代码生成'
|
||||
version = '0.0.2'
|
||||
version = '0.0.3'
|
||||
description = '生成通用业务代码'
|
||||
author = 'wu-clan'
|
||||
|
||||
|
||||
@@ -14,12 +14,12 @@ class GenBusinessSchemaBase(SchemaBase):
|
||||
table_name: str = Field(description='表名称(英文)')
|
||||
doc_comment: str = Field(description='文档注释(用于函数/参数文档)')
|
||||
table_comment: str | None = Field(None, description='表描述')
|
||||
class_name: str | None = Field(None, description='基础类名 (默认为英文表名称)')
|
||||
schema_name: str | None = Field(None, description='Schema 名称 (默认为英文表名称)')
|
||||
filename: str | None = Field(None, description='基础文件名(默认为英文表名称)')
|
||||
class_name: str | None = Field(None, description='用于 python 代码基础类名')
|
||||
schema_name: str | None = Field(None, description='用于 python Schema 代码基础类名')
|
||||
filename: str | None = Field(None, description='用于 python 代码基础文件名')
|
||||
default_datetime_column: bool = Field(True, description='是否存在默认时间列')
|
||||
api_version: str = Field('v1', description='代码生成 api 版本')
|
||||
gen_path: str | None = Field(None, description='代码生成路径(默认为 app 根路径)')
|
||||
gen_path: str | None = Field(None, description='代码生成路径')
|
||||
remark: str | None = Field(None, description='备注')
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from backend.common.schema import SchemaBase
|
||||
from backend.plugin.code_generator.utils.type_conversion import sql_type_to_sqlalchemy
|
||||
|
||||
|
||||
class GenModelSchemaBase(SchemaBase):
|
||||
class GenColumnSchemaBase(SchemaBase):
|
||||
"""代码生成模型基础模型"""
|
||||
|
||||
name: str = Field(description='列名称')
|
||||
@@ -26,16 +26,16 @@ class GenModelSchemaBase(SchemaBase):
|
||||
return sql_type_to_sqlalchemy(v)
|
||||
|
||||
|
||||
class CreateGenModelParam(GenModelSchemaBase):
|
||||
"""创建代码生成模型参数"""
|
||||
class CreateGenColumnParam(GenColumnSchemaBase):
|
||||
"""创建代码生成模型列参数"""
|
||||
|
||||
|
||||
class UpdateGenModelParam(GenModelSchemaBase):
|
||||
"""更新代码生成模型参数"""
|
||||
class UpdateGenColumnParam(GenColumnSchemaBase):
|
||||
"""更新代码生成模型列参数"""
|
||||
|
||||
|
||||
class GetGenModelDetail(GenModelSchemaBase):
|
||||
"""获取代码生成模型详情"""
|
||||
class GetGenColumnDetail(GenColumnSchemaBase):
|
||||
"""获取代码生成模型列详情"""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from typing import Sequence
|
||||
|
||||
from sqlalchemy import Select
|
||||
|
||||
@@ -27,6 +28,12 @@ class GenBusinessService:
|
||||
raise errors.NotFoundError(msg='代码生成业务不存在')
|
||||
return business
|
||||
|
||||
@staticmethod
|
||||
async def get_all() -> Sequence[GenBusiness]:
|
||||
"""获取所有业务"""
|
||||
async with async_db_session() as db:
|
||||
return await gen_business_dao.get_all(db)
|
||||
|
||||
@staticmethod
|
||||
async def get_select(*, table_name: str) -> Select:
|
||||
"""
|
||||
|
||||
@@ -10,18 +10,19 @@ from typing import Sequence
|
||||
import aiofiles
|
||||
|
||||
from pydantic.alias_generators import to_pascal
|
||||
from sqlalchemy import RowMapping
|
||||
|
||||
from backend.common.exception import errors
|
||||
from backend.core.path_conf import BASE_PATH
|
||||
from backend.database.db import async_db_session
|
||||
from backend.plugin.code_generator.crud.crud_business import gen_business_dao
|
||||
from backend.plugin.code_generator.crud.crud_code import gen_dao
|
||||
from backend.plugin.code_generator.crud.crud_column import gen_model_dao
|
||||
from backend.plugin.code_generator.crud.crud_column import gen_column_dao
|
||||
from backend.plugin.code_generator.model import GenBusiness
|
||||
from backend.plugin.code_generator.schema.business import CreateGenBusinessParam
|
||||
from backend.plugin.code_generator.schema.code import ImportParam
|
||||
from backend.plugin.code_generator.schema.column import CreateGenModelParam
|
||||
from backend.plugin.code_generator.service.column_service import gen_model_service
|
||||
from backend.plugin.code_generator.schema.column import CreateGenColumnParam
|
||||
from backend.plugin.code_generator.service.column_service import gen_column_service
|
||||
from backend.plugin.code_generator.utils.code_template import gen_template
|
||||
from backend.plugin.code_generator.utils.type_conversion import sql_type_to_pydantic
|
||||
|
||||
@@ -30,7 +31,7 @@ class GenService:
|
||||
"""代码生成服务类"""
|
||||
|
||||
@staticmethod
|
||||
async def get_tables(*, table_schema: str) -> Sequence[str]:
|
||||
async def get_tables(*, table_schema: str) -> Sequence[RowMapping]:
|
||||
"""
|
||||
获取指定 schema 下的所有表名
|
||||
|
||||
@@ -43,7 +44,7 @@ class GenService:
|
||||
@staticmethod
|
||||
async def import_business_and_model(*, obj: ImportParam) -> None:
|
||||
"""
|
||||
导入业务和模型数据
|
||||
导入业务和模型列数据
|
||||
|
||||
:param obj: 导入参数对象
|
||||
:return:
|
||||
@@ -64,8 +65,8 @@ class GenService:
|
||||
table_name=table_name,
|
||||
doc_comment=table_info[1] or table_name.split('_')[-1],
|
||||
table_comment=table_info[1],
|
||||
class_name=table_name,
|
||||
schema_name=table_name,
|
||||
class_name=to_pascal(table_name),
|
||||
schema_name=to_pascal(table_name),
|
||||
filename=table_name,
|
||||
).model_dump()
|
||||
)
|
||||
@@ -76,9 +77,9 @@ class GenService:
|
||||
for column in column_info:
|
||||
column_type = column[-1].split('(')[0].upper()
|
||||
pd_type = sql_type_to_pydantic(column_type)
|
||||
await gen_model_dao.create(
|
||||
await gen_column_dao.create(
|
||||
db,
|
||||
CreateGenModelParam(
|
||||
CreateGenColumnParam(
|
||||
name=column[0],
|
||||
comment=column[-2],
|
||||
type=column_type,
|
||||
@@ -99,7 +100,7 @@ class GenService:
|
||||
:param business: 业务对象
|
||||
:return:
|
||||
"""
|
||||
gen_models = await gen_model_service.get_models(business_id=business.id)
|
||||
gen_models = await gen_column_service.get_columns(business_id=business.id)
|
||||
if not gen_models:
|
||||
raise errors.NotFoundError(msg='代码生成模型表为空')
|
||||
|
||||
@@ -126,7 +127,20 @@ class GenService:
|
||||
codes = {}
|
||||
for tpl, code in tpl_code_map.items():
|
||||
if tpl.startswith('python'):
|
||||
codes[tpl.replace('.jinja', '.py').split('/')[-1]] = code.encode('utf-8')
|
||||
rootpath = f'fastapi_best_architecture/backend/app/{business.app_name}'
|
||||
template_name = tpl.split('/')[-1]
|
||||
match template_name:
|
||||
case 'api.jinja':
|
||||
filepath = f'{rootpath}/api/{business.api_version}/{business.app_name}.py'
|
||||
case 'crud.jinja':
|
||||
filepath = f'{rootpath}/crud/crud_{business.app_name}.py'
|
||||
case 'model.jinja':
|
||||
filepath = f'{rootpath}/model/{business.app_name}.py'
|
||||
case 'schema.jinja':
|
||||
filepath = f'{rootpath}/schema/{business.app_name}.py'
|
||||
case 'service.jinja':
|
||||
filepath = f'{rootpath}/service/{business.app_name}_service.py'
|
||||
codes[filepath] = code.encode('utf-8')
|
||||
|
||||
return codes
|
||||
|
||||
|
||||
@@ -4,93 +4,93 @@ from typing import Sequence
|
||||
|
||||
from backend.common.exception import errors
|
||||
from backend.database.db import async_db_session
|
||||
from backend.plugin.code_generator.crud.crud_column import gen_model_dao
|
||||
from backend.plugin.code_generator.enums import GenModelMySQLColumnType
|
||||
from backend.plugin.code_generator.crud.crud_column import gen_column_dao
|
||||
from backend.plugin.code_generator.enums import GenMySQLColumnType
|
||||
from backend.plugin.code_generator.model import GenColumn
|
||||
from backend.plugin.code_generator.schema.column import CreateGenModelParam, UpdateGenModelParam
|
||||
from backend.plugin.code_generator.schema.column import CreateGenColumnParam, UpdateGenColumnParam
|
||||
from backend.plugin.code_generator.utils.type_conversion import sql_type_to_pydantic
|
||||
|
||||
|
||||
class GenModelService:
|
||||
"""代码生成模型服务类"""
|
||||
class GenColumnService:
|
||||
"""代码生成模型列服务类"""
|
||||
|
||||
@staticmethod
|
||||
async def get(*, pk: int) -> GenColumn:
|
||||
"""
|
||||
获取指定 ID 的模型
|
||||
获取指定 ID 的模型列
|
||||
|
||||
:param pk: 模型 ID
|
||||
:param pk: 模型列 ID
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session() as db:
|
||||
model = await gen_model_dao.get(db, pk)
|
||||
if not model:
|
||||
raise errors.NotFoundError(msg='代码生成模型不存在')
|
||||
return model
|
||||
column = await gen_column_dao.get(db, pk)
|
||||
if not column:
|
||||
raise errors.NotFoundError(msg='代码生成模型列不存在')
|
||||
return column
|
||||
|
||||
@staticmethod
|
||||
async def get_types() -> list[str]:
|
||||
"""获取所有 MySQL 列类型"""
|
||||
types = GenModelMySQLColumnType.get_member_keys()
|
||||
types = GenMySQLColumnType.get_member_keys()
|
||||
types.sort()
|
||||
return types
|
||||
|
||||
@staticmethod
|
||||
async def get_models(*, business_id: int) -> Sequence[GenColumn]:
|
||||
async def get_columns(*, business_id: int) -> Sequence[GenColumn]:
|
||||
"""
|
||||
获取指定业务的所有模型
|
||||
获取指定业务的所有模型列
|
||||
|
||||
:param business_id: 业务 ID
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session() as db:
|
||||
return await gen_model_dao.get_all_by_business(db, business_id)
|
||||
return await gen_column_dao.get_all_by_business(db, business_id)
|
||||
|
||||
@staticmethod
|
||||
async def create(*, obj: CreateGenModelParam) -> None:
|
||||
async def create(*, obj: CreateGenColumnParam) -> None:
|
||||
"""
|
||||
创建模型
|
||||
创建模型列
|
||||
|
||||
:param obj: 创建模型参数
|
||||
:param obj: 创建模型列参数
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session.begin() as db:
|
||||
gen_models = await gen_model_dao.get_all_by_business(db, obj.gen_business_id)
|
||||
if obj.name in [gen_model.name for gen_model in gen_models]:
|
||||
raise errors.ForbiddenError(msg='禁止添加相同列到同一模型表')
|
||||
gen_columns = await gen_column_dao.get_all_by_business(db, obj.gen_business_id)
|
||||
if obj.name in [gen_column.name for gen_column in gen_columns]:
|
||||
raise errors.ForbiddenError(msg='模型列已存在')
|
||||
|
||||
pd_type = sql_type_to_pydantic(obj.type)
|
||||
await gen_model_dao.create(db, obj, pd_type=pd_type)
|
||||
await gen_column_dao.create(db, obj, pd_type=pd_type)
|
||||
|
||||
@staticmethod
|
||||
async def update(*, pk: int, obj: UpdateGenModelParam) -> int:
|
||||
async def update(*, pk: int, obj: UpdateGenColumnParam) -> int:
|
||||
"""
|
||||
更新模型
|
||||
更新模型列
|
||||
|
||||
:param pk: 模型 ID
|
||||
:param obj: 更新模型参数
|
||||
:param pk: 模型列 ID
|
||||
:param obj: 更新模型列参数
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session.begin() as db:
|
||||
model = await gen_model_dao.get(db, pk)
|
||||
if obj.name != model.name:
|
||||
gen_models = await gen_model_dao.get_all_by_business(db, obj.gen_business_id)
|
||||
if obj.name in [gen_model.name for gen_model in gen_models]:
|
||||
column = await gen_column_dao.get(db, pk)
|
||||
if obj.name != column.name:
|
||||
gen_columns = await gen_column_dao.get_all_by_business(db, obj.gen_business_id)
|
||||
if obj.name in [gen_column.name for gen_column in gen_columns]:
|
||||
raise errors.ConflictError(msg='模型列名已存在')
|
||||
|
||||
pd_type = sql_type_to_pydantic(obj.type)
|
||||
return await gen_model_dao.update(db, pk, obj, pd_type=pd_type)
|
||||
return await gen_column_dao.update(db, pk, obj, pd_type=pd_type)
|
||||
|
||||
@staticmethod
|
||||
async def delete(*, pk: int) -> int:
|
||||
"""
|
||||
删除模型
|
||||
删除模型列
|
||||
|
||||
:param pk: 模型 ID
|
||||
:param pk: 模型列 ID
|
||||
:return:
|
||||
"""
|
||||
async with async_db_session.begin() as db:
|
||||
return await gen_model_dao.delete(db, pk)
|
||||
return await gen_column_dao.delete(db, pk)
|
||||
|
||||
|
||||
gen_model_service: GenModelService = GenModelService()
|
||||
gen_column_service: GenColumnService = GenColumnService()
|
||||
|
||||
@@ -23,7 +23,7 @@ class CRUD{{ class_name }}(CRUDPlus[{{ schema_name }}]):
|
||||
|
||||
async def get_list(self) -> Select:
|
||||
"""获取{{ doc_comment }}列表"""
|
||||
return await self.select_order('created_time', 'desc')
|
||||
return await self.select_order('id', 'desc')
|
||||
|
||||
async def get_all(self, db: AsyncSession) -> Sequence[{{ class_name }}]:
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from backend.core.conf import settings
|
||||
from backend.plugin.code_generator.enums import GenModelMySQLColumnType, GenModelPostgreSQLColumnType
|
||||
from backend.plugin.code_generator.enums import GenMySQLColumnType, GenPostgreSQLColumnType
|
||||
|
||||
|
||||
def sql_type_to_sqlalchemy(typing: str) -> str:
|
||||
@@ -12,10 +12,10 @@ def sql_type_to_sqlalchemy(typing: str) -> str:
|
||||
:return:
|
||||
"""
|
||||
if settings.DATABASE_TYPE == 'mysql':
|
||||
if typing in GenModelMySQLColumnType.get_member_keys():
|
||||
if typing in GenMySQLColumnType.get_member_keys():
|
||||
return typing
|
||||
else:
|
||||
if typing in GenModelPostgreSQLColumnType.get_member_keys():
|
||||
if typing in GenPostgreSQLColumnType.get_member_keys():
|
||||
return typing
|
||||
return 'String'
|
||||
|
||||
@@ -29,9 +29,9 @@ def sql_type_to_pydantic(typing: str) -> str:
|
||||
"""
|
||||
try:
|
||||
if settings.DATABASE_TYPE == 'mysql':
|
||||
return GenModelMySQLColumnType[typing].value
|
||||
return GenMySQLColumnType[typing].value
|
||||
if typing == 'CHARACTER VARYING': # postgresql 中 DDL VARCHAR 的别名
|
||||
return 'str'
|
||||
return GenModelPostgreSQLColumnType[typing].value
|
||||
return GenPostgreSQLColumnType[typing].value
|
||||
except KeyError:
|
||||
return 'str'
|
||||
|
||||
Reference in New Issue
Block a user