359 lines
11 KiB
Markdown
359 lines
11 KiB
Markdown
:::tip 本章概要
|
||
以 fastapi_example 演示表为完整案例,演示从建表到生成到使用的全流程。
|
||
:::
|
||
|
||
# 实战案例
|
||
|
||
以 `fastapi_example` 演示表为完整案例,演示从建表到生成到使用的全流程。
|
||
|
||
## 第 1 步:创建数据表
|
||
|
||
在数据库中执行建表语句:
|
||
|
||
```sql
|
||
CREATE TABLE `fastapi_example` (
|
||
`id` int NOT NULL AUTO_INCREMENT,
|
||
`name` varchar(100) NOT NULL COMMENT '案例名称',
|
||
`code` varchar(50) NOT NULL COMMENT '案例编码',
|
||
`type` int DEFAULT 1 COMMENT '案例类型:1-类型1 2-类型2 3-类型3',
|
||
`status` int DEFAULT 1 COMMENT '案例状态:1-正常 2-停用',
|
||
`sort` int DEFAULT 0 COMMENT '排序',
|
||
`cover` varchar(255) DEFAULT NULL COMMENT '封面图',
|
||
`content` text COMMENT '案例内容',
|
||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||
`create_user` varchar(50) DEFAULT NULL,
|
||
`create_time` datetime DEFAULT NULL,
|
||
`update_user` varchar(50) DEFAULT NULL,
|
||
`update_time` datetime DEFAULT NULL,
|
||
`is_delete` int DEFAULT 0,
|
||
PRIMARY KEY (`id`)
|
||
) COMMENT='案例表';
|
||
```
|
||
|
||
## 第 2 步:预览配置
|
||
|
||
```bash
|
||
python generator.py fastapi_example --dry-run
|
||
```
|
||
|
||
输出:
|
||
|
||
```
|
||
==============================================================
|
||
数据库表结构解析和代码生成工具
|
||
==============================================================
|
||
正在解析表: fastapi_example
|
||
表结构解析成功
|
||
|
||
------------------------------------------------------------
|
||
生成配置摘要:
|
||
------------------------------------------------------------
|
||
应用名称: example
|
||
模块名称: 案例
|
||
模型类名: Example
|
||
字段数量: 8
|
||
是否有排序: True
|
||
是否有状态: True
|
||
- name: 案例名称 (String)
|
||
- code: 案例编码 (String)
|
||
- type: 案例类型 (Integer)
|
||
选项: [(1, '类型1'), (2, '类型2'), (3, '类型3')]
|
||
- status: 案例状态 (Integer)
|
||
选项: [(1, '正常'), (2, '停用')]
|
||
- sort: 排序 (Integer)
|
||
... 还有 3 个字段
|
||
|
||
==============================================================
|
||
预览模式 - 不执行代码生成(去掉 --dry-run 参数即可生成)
|
||
==============================================================
|
||
```
|
||
|
||
## 第 3 步:生成代码
|
||
|
||
```bash
|
||
python generator.py fastapi_example
|
||
```
|
||
|
||
输出:
|
||
|
||
```
|
||
==============================================================
|
||
数据库表结构解析和代码生成工具
|
||
==============================================================
|
||
正在解析表: fastapi_example
|
||
表结构解析成功
|
||
...
|
||
创建输出目录: src/modules/example
|
||
生成文件: src/modules/example/__init__.py
|
||
生成文件: src/modules/example/models.py
|
||
生成文件: src/modules/example/schemas.py
|
||
生成文件: src/modules/example/repository.py
|
||
生成文件: src/modules/example/service.py
|
||
生成文件: src/api/v1/endpoints/example.py
|
||
生成文件: ui/src/views/tool/example/index.vue
|
||
生成文件: ui/src/views/tool/example/edit.vue
|
||
生成文件: ui/src/views/tool/example/detail.vue
|
||
生成文件: ui/src/views/tool/example/querySchemas.ts
|
||
生成文件: ui/src/views/tool/example/columns.ts
|
||
生成文件: ui/src/api/tool/example.ts
|
||
已更新路由注册: src/api/v1/router.py
|
||
已自动创建菜单: 案例(10 个权限节点)
|
||
代码生成完成!
|
||
```
|
||
|
||
## 第 4 步:验证生成结果
|
||
|
||
### 检查后端文件
|
||
|
||
```bash
|
||
ls src/modules/example/
|
||
# __init__.py models.py repository.py schemas.py service.py
|
||
|
||
ls src/api/v1/endpoints/example.py
|
||
# example.py
|
||
```
|
||
|
||
### 检查前端文件
|
||
|
||
```bash
|
||
ls ui/src/views/tool/example/
|
||
# index.vue edit.vue detail.vue columns.ts querySchemas.ts
|
||
|
||
ls ui/src/api/tool/example.ts
|
||
# example.ts
|
||
```
|
||
|
||
### 检查路由注册
|
||
|
||
在 `src/api/v1/router.py` 中应新增:
|
||
|
||
```python
|
||
from api.v1.endpoints.example import router as example_router
|
||
...
|
||
v1.include_router(example_router, prefix="/example", tags=["案例"])
|
||
```
|
||
|
||
## 第 5 步:重启后端
|
||
|
||
```bash
|
||
python src/main.py
|
||
```
|
||
|
||
## 第 6 步:访问页面
|
||
|
||
1. 登录管理后台
|
||
2. 左侧菜单找到「开发工具 → 案例」
|
||
3. 进入案例管理页面,测试增删改查功能
|
||
|
||

|
||
|
||
## 生成代码逐文件解析
|
||
|
||
### models.py
|
||
|
||
```python
|
||
class Example(base_model, base_db):
|
||
__tablename__ = DB_PREFIX + "example"
|
||
|
||
name = Column(String(100), nullable=False, comment="案例名称")
|
||
code = Column(String(50), nullable=False, comment="案例编码")
|
||
type = Column(Integer, default=1, comment="案例类型:1-类型1 2-类型2 3-类型3")
|
||
status = Column(Integer, default=1, comment="案例状态:1-正常 2-停用")
|
||
sort = Column(Integer, default=0, comment="排序")
|
||
cover = Column(String(255), nullable=True, comment="封面图")
|
||
content = Column(Text, nullable=True, comment="案例内容")
|
||
remark = Column(String(500), nullable=True, comment="备注")
|
||
```
|
||
|
||
- 自动映射字段类型(varchar→String, int→Integer, text→Text)
|
||
- 自动识别 `cover` 为图片字段
|
||
- 自动识别 `content` 为富文本字段(注释含"内容"关键词)
|
||
- 系统字段(id/create_user/create_time 等)由基类提供,不重复定义
|
||
|
||
### schemas.py
|
||
|
||
```python
|
||
class ExampleForm(BaseModel):
|
||
id: Optional[int] = Field(None, description="案例ID")
|
||
name: str = Field(..., min_length=1, max_length=100, description="案例名称")
|
||
code: str = Field(..., min_length=1, max_length=50, description="案例编码")
|
||
type: int = Field(..., description="案例类型:1-类型1 2-类型2 3-类型3")
|
||
status: int = Field(..., description="案例状态:1-正常 2-停用")
|
||
sort: int = Field(..., description="排序")
|
||
cover: Optional[str] = Field(None, max_length=255, description="封面图")
|
||
content: Optional[str] = Field(None, description="案例内容")
|
||
remark: Optional[str] = Field(None, max_length=500, description="备注")
|
||
|
||
class ExampleStatusForm(BaseModel):
|
||
id: int = Field(..., gt=0, description="案例ID")
|
||
status: int = Field(..., ge=1, le=2, description="案例状态:1-正常 2-停用")
|
||
```
|
||
|
||
- `name`/`code`/`type`/`status`/`sort` 为必填(`...`)
|
||
- `cover`/`content`/`remark` 为可选(`Optional`)
|
||
- 自动生成 `StatusForm`(因为有 `status` 字段)
|
||
|
||
### service.py
|
||
|
||
```python
|
||
class ExampleService(BaseService[Example]):
|
||
repo = example_repo
|
||
model = Example
|
||
page_like_fields = ('name', 'code', 'remark')
|
||
page_eq_fields = ('type', 'status')
|
||
page_order_by = (('sort', 'asc'), ('id', 'desc'))
|
||
file_fields = ('cover',)
|
||
serialize_maps = {'type': 'example_type', 'status': 'example_status'}
|
||
|
||
example_service = ExampleService()
|
||
```
|
||
|
||
- `name`/`code`/`remark` 为模糊查询字段(字符串类型)
|
||
- `type`/`status` 为精确匹配字段(有选项)
|
||
- 默认按 `sort` 升序、`id` 降序排列
|
||
- `cover` 标记为文件字段(自动处理上传和 URL)
|
||
- `serialize_maps` 自动关联数据字典
|
||
|
||
### endpoint.py
|
||
|
||
```python
|
||
@router.get('/page')
|
||
@permission_required("sys:example:page")
|
||
def page(request: Request):
|
||
return example_service.get_page(request)
|
||
|
||
@router.post('/add')
|
||
@permission_required("sys:example:add")
|
||
@check_demo
|
||
def add(request: Request, data: ExampleForm):
|
||
return example_service.add(request, data)
|
||
|
||
# ... update / delete / batchDelete / status / detail / list
|
||
```
|
||
|
||
- 自动生成 8 个端点(page/detail/list/add/update/delete/batchDelete/status)
|
||
- 写操作自动加 `@check_demo` 装饰器
|
||
|
||
## 批量生成示例
|
||
|
||
创建第二张表:
|
||
|
||
```sql
|
||
CREATE TABLE `fastapi_product` (
|
||
`id` int NOT NULL AUTO_INCREMENT,
|
||
`name` varchar(200) NOT NULL COMMENT '商品名称',
|
||
`price` decimal(10,2) DEFAULT 0 COMMENT '价格',
|
||
`stock` int DEFAULT 0 COMMENT '库存',
|
||
`status` int DEFAULT 1 COMMENT '状态:1-上架 2-下架',
|
||
`sort` int DEFAULT 0 COMMENT '排序',
|
||
`create_user` varchar(50) DEFAULT NULL,
|
||
`create_time` datetime DEFAULT NULL,
|
||
`update_user` varchar(50) DEFAULT NULL,
|
||
`update_time` datetime DEFAULT NULL,
|
||
`is_delete` int DEFAULT 0,
|
||
PRIMARY KEY (`id`)
|
||
) COMMENT='商品表';
|
||
```
|
||
|
||
Web 界面批量生成:
|
||
|
||

|
||
|
||
```json
|
||
{
|
||
"tableNames": [
|
||
"fastapi_example|案例表",
|
||
"fastapi_product|商品表"
|
||
]
|
||
}
|
||
```
|
||
|
||
CLI 循环生成:
|
||
|
||
```bash
|
||
python generator.py fastapi_example
|
||
python generator.py fastapi_product
|
||
```
|
||
|
||
## 树状表示例
|
||
|
||
当表中包含 `parent_id` 或 `pid` 字段时,生成器自动切换为树状模板。
|
||
|
||
### 创建树状表
|
||
|
||
```sql
|
||
CREATE TABLE `fastapi_category` (
|
||
`id` int NOT NULL AUTO_INCREMENT,
|
||
`name` varchar(100) NOT NULL COMMENT '分类名称',
|
||
`parent_id` int DEFAULT 0 COMMENT '父级ID(0为顶级)',
|
||
`sort` int DEFAULT 0 COMMENT '排序',
|
||
`status` int DEFAULT 1 COMMENT '状态:1-正常 2-停用',
|
||
`create_user` varchar(50) DEFAULT NULL,
|
||
`create_time` datetime DEFAULT NULL,
|
||
`update_user` varchar(50) DEFAULT NULL,
|
||
`update_time` datetime DEFAULT NULL,
|
||
`is_delete` int DEFAULT 0,
|
||
PRIMARY KEY (`id`)
|
||
) COMMENT='分类表';
|
||
```
|
||
|
||
### 生成结果差异
|
||
|
||
因为表中包含 `parent_id` 字段,生成器自动:
|
||
|
||
1. **前端模板切换**:使用 `ui2/` 树形模板替代 `ui/` 普通列表模板
|
||
2. **生成文件减少**:不生成 `columns.ts` 和 `querySchemas.ts`(树形组件内联列定义)
|
||
3. **数据加载方式**:全量加载 + 前端 `buildTree` 构建树形结构
|
||
4. **交互差异**:支持展开/折叠、父子级联选择
|
||
|
||
```
|
||
普通列表(ui/) 树状列表(ui2/)
|
||
├── index.vue ├── index.vue(内联列 + buildTree)
|
||
├── edit.vue ├── edit.vue(含父级选择)
|
||
├── detail.vue ├── detail.vue
|
||
├── columns.ts └── (无 columns.ts)
|
||
├── querySchemas.ts └── (无 querySchemas.ts)
|
||
└── api.ts └── api.ts(共用)
|
||
```
|
||
|
||
## 生成后的自定义
|
||
|
||
代码生成后,通常需要根据业务需求进行微调:
|
||
|
||
### 常见自定义项
|
||
|
||
| 自定义项 | 涉及文件 | 说明 |
|
||
|:----|:----|:----|
|
||
| 添加业务校验 | `schemas.py` | 添加 `@field_validator` 自定义校验逻辑 |
|
||
| 添加删除前检查 | `service.py` | 覆盖 `_before_delete` 钩子 |
|
||
| 添加创建前处理 | `service.py` | 覆盖 `_before_add` 钩子(如密码哈希) |
|
||
| 修改序列化 | `service.py` | 覆盖 `_serialize` 钩子(如关联查询) |
|
||
| 添加自定义接口 | `endpoint.py` | 新增路由方法 |
|
||
| 调整前端布局 | `index.vue` | 修改表格列宽、操作按钮等 |
|
||
| 调整表单校验 | `edit.vue` | 修改表单规则、默认值等 |
|
||
|
||
### 示例:添加删除前检查
|
||
|
||
```python
|
||
# src/modules/example/service.py
|
||
class ExampleService(BaseService[Example]):
|
||
# ... 原有配置 ...
|
||
|
||
def _before_delete(self, ids) -> Optional[str]:
|
||
"""删除前校验:检查是否有关联数据"""
|
||
# 示例:检查是否有子分类
|
||
id_list = parse_id_list(str(ids))
|
||
if id_list and self.repo.filter(
|
||
Example.parent_id.in_(id_list), Example.is_delete == 0
|
||
).first():
|
||
return "存在子分类,请先删除子分类"
|
||
return None
|
||
```
|
||
|
||
## 总结
|
||
|
||
通过以上 6 步即可完成一个完整业务模块的生成:
|
||
1. 建表 → 2. 预览 → 3. 生成 → 4. 验证 → 5. 重启 → 6. 使用
|
||
|
||
整个过程约 1 分钟,生成约 12 个文件、500+ 行代码,涵盖后端三层 + 前端页面 + 路由注册 + 菜单权限。生成后根据业务需求进行微调即可投入使用。
|