签入版本

This commit is contained in:
2026-09-12 23:12:15 +08:00
commit 91998056ca
1841 changed files with 341325 additions and 0 deletions
@@ -0,0 +1,191 @@
:::tip 本章概要
代码生成器 CLI 模式的使用方法,包括单表生成、批量生成、预览模式和配置导出。
:::
# CLI 命令行使用
CLI 入口为项目根目录的 `generator.py`,内部复用 `src/modules/generator` 下的引擎。适合开发阶段快速生成单个模块。
## 基本用法
```bash
# 解析表结构并生成模块(最常用)
python generator.py fastapi_example
```
执行后自动完成:
1. 从数据库解析 `fastapi_example` 表结构
2. 生成后端模块代码到 `src/modules/example/`
3. 生成端点代码到 `src/api/v1/endpoints/example.py`
4. 生成前端页面到 `ui/src/views/tool/example/` 和 `ui/src/api/tool/example.ts`
5. 自动注册路由到 `src/api/v1/router.py`
6. 自动创建菜单和权限节点
## 预览模式
使用 `--dry-run` 仅解析表结构并打印配置摘要,不执行代码生成:
```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 参数即可生成)
==============================================================
```
## 导出配置
使用 `--output` 将解析结果导出为 JSON 配置文件:
```bash
# 预览并导出配置
python generator.py fastapi_example --dry-run --output config.json
# 生成代码并同时保存配置
python generator.py fastapi_example --output config.json
```
导出的 `config.json` 包含完整的生成配置,可手动编辑后重新使用。
## 使用配置文件生成
使用 `--config` 加载已有的 JSON 配置文件,跳过表解析:
```bash
python generator.py --config config.json
```
适用场景:
- 需要微调字段配置后重新生成
- 表结构已不存在但配置文件保留
- 跨项目复用配置
## 完整参数
| 参数 | 简写 | 说明 |
|:----|:----|:----|
| `table_name` | - | 数据库表名(位置参数,可选) |
| `--config` | `-c` | 使用已有的 JSON 配置文件(跳过表解析) |
| `--dry-run` | `-d` | 仅生成配置,不执行代码生成 |
| `--output` | `-o` | 将配置导出为 JSON 文件 |
## 典型工作流
### 快速生成
```bash
python generator.py fastapi_example
```
### 预览 → 微调 → 生成
```bash
# 1. 预览配置
python generator.py fastapi_example --dry-run --output config.json
# 2. 编辑 config.json(调整字段属性、注释等)
vim config.json
# 3. 用配置文件生成
python generator.py --config config.json
```
### 仅保存配置
```bash
python generator.py fastapi_example --output config.json
```
## 环境要求
运行 CLI 前需确保:
1. **数据库可访问**:CLI 复用 `.env` 中的数据库配置,需确保 MySQL 服务正常且连接信息正确
2. **Python 依赖已安装**:`pip install -r requirements.txt`(包含 Jinja2、SQLAlchemy 等)
3. **表已存在**:目标表需已在数据库中创建完成
4. **编码要求**:Windows 环境下确保终端使用 UTF-8 编码(`chcp 65001`)
:::warning 数据库要求
CLI 命令行工具通过查询 MySQL 的 `information_schema` 获取表结构信息,**仅支持 MySQL 数据库**。
:::
## 常见错误
### 表不存在
```
操作失败: 表 fastapi_xxx 不存在或无业务字段
```
**原因**:数据库中不存在该表,或表名拼写错误。
**解决**:确认表名正确,且表已在数据库中创建。
### 目标目录已存在
```
操作失败: 模块 example 已存在,请先删除 src/modules/example
```
**原因**:`src/modules/example/` 目录已存在,生成器拒绝覆盖。
**解决**:删除已有目录后重新生成(详见 [6.9 常见问题](/zh/volume5/faq))。
### 数据库连接失败
```
操作失败: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server...")
```
**原因**:`.env` 中的数据库配置错误,或 MySQL 服务未启动。
**解决**:检查 `.env` 中的 `DB_HOST`、`DB_PORT`、`DB_USERNAME`、`DB_PASSWORD` 配置。
### 编码错误
```
SyntaxError: Non-UTF-8 code start with '\xc8' in file ...
```
**原因**:Windows 终端编码不是 UTF-8。
**解决**:执行 `chcp 65001` 切换终端编码。
## 注意事项
1. **表名支持带前缀**:`fastapi_example` 和 `example` 都可以,脚本会自动处理 `fastapi_` 前缀
2. **目标目录不能已存在**:如果 `src/modules/example/` 已存在,会报错提示先删除
3. **数据库连接**:CLI 复用 `.env` 中的数据库配置,确保数据库可正常访问
4. **编码要求**:Windows 环境下确保终端使用 UTF-8 编码(`chcp 65001`)
## 总结
CLI 命令行模式通过 `python generator.py` 启动,支持单表生成、批量生成、预览模式和配置导出。生成前自动检测目标目录是否已存在,避免覆盖已有代码。
@@ -0,0 +1,201 @@
:::tip 本章概要
代码生成引擎的工作原理,包括配置解析、模板渲染、文件写入和自动注册的完整流程。
:::
# 代码生成引擎
`src/modules/generator/code_generator.py` 是代码生成器的执行层,负责接收配置字典、渲染模板、写入文件、自动注册路由和菜单。
## 核心类:CodeGenerator
```python
from modules.generator.code_generator import CodeGenerator
generator = CodeGenerator(config)
generator.generate(auto=True)
```
### 构造参数
| 参数 | 说明 |
|:----|:----|
| `config` | 配置字典(由 `parser.parse()` 或 JSON 文件提供) |
构造时自动:
- 调用 `normalize_config()` 标准化配置(幂等,已标准化的配置原样返回)
- 设置输出目录:`src/modules/{app_name}`
- 初始化 Jinja2 模板环境(`trim_blocks=True`, `lstrip_blocks=True`)
## generate() 主方法
```python
def generate(self, auto=False, request=None):
```
### 执行流程
```
1. 校验输出目录不存在(避免覆盖已有模块)
2. 创建输出目录 src/modules/{app_name}/
3. 准备模板上下文数据
4. 渲染后端模板 → 写入 modules 目录
5. 渲染 endpoint 模板 → 写入 api/v1/endpoints/ 目录
6. 渲染前端模板 → 写入 ui/src/views/ 和 ui/src/api/
7. 自动注册到 router.py
8. 自动创建菜单 + 权限节点
```
### 参数
| 参数 | 说明 |
|:----|:----|
| `auto` | 自动模式(当前无交互差异) |
| `request` | FastAPI 请求对象(用于获取操作人信息) |
## 配置标准化
`normalize_config()` 将 parser 产出的配置转为模板可用的标准格式:
```python
# parser 产出的字段
{"name": "type", "db_type": "Integer", "comment": "案例类型:1-类型1 2-类型2"}
# 标准化后
{
"name": "type",
"camel_name": "type", # 驼峰命名
"db_type": "Integer",
"form_type": "int", # Pydantic 类型
"comment": "案例类型:1-类型1 2-类型2",
"py_comment": "案例类型:1-类型1 2-类型2", # 转义后
"default_repr": "1", # 默认值表示
"is_status": False, # 状态字段标识
"is_sort": False, # 排序字段标识
}
```
## 模板上下文
### _prepare_context()
准备后端模板的渲染上下文:
| 变量 | 类型 | 说明 |
|:----|:----|:----|
| `app_name` | str | 模块名(如 `example`) |
| `module_comment` | str | 中文名(如 `案例`) |
| `model_class_name` | str | 类名(如 `Example`) |
| `permission_prefix` | str | 权限前缀(如 `sys:example`) |
| `display_field` | str | 显示字段(如 `name`) |
| `has_sort` | bool | 有排序字段 |
| `has_status` | bool | 有状态字段 |
| `has_status_route` | bool | 生成状态路由 |
| `has_image_field` | bool | 有图片字段 |
| `has_rich_text_field` | bool | 有富文本字段 |
| `serialize_maps` | dict | 枚举映射 |
| `sort_field` | str | 排序字段名 |
| `fields` | list | 全部字段 |
| `form_fields` | list | 表单字段 |
| `filter_fields` | list | 精确匹配字段 |
| `like_fields` | list | 模糊查询字段 |
### _prepare_vue_context()
在后端上下文基础上扩展前端专用变量:
| 变量 | 类型 | 说明 |
|:----|:----|:----|
| `module_name` | str | 驼峰模块名 |
| `model_class_name_camel` | str | 驼峰类名(首字母小写) |
| `list_fields` | list | 列表展示字段 |
| `searchable_fields` | list | 可搜索字段 |
| `editable_fields` | list | 可编辑字段 |
| `has_export` | bool | 有导出功能 |
| `route_prefix` | str | 路由前缀 |
| `api_path` | str | API 路径 |
| `is_tree_structure` | bool | 是否树形结构 |
| `parent_id_field` | str | 父级字段名 |
| `has_search_form` | bool | 显示搜索表单 |
| `show_selection` | bool | 显示复选框 |
## 文件生成
### 后端文件
| 模板 | 输出路径 | 说明 |
|:----|:----|:----|
| `__init__.py.tpl` | `src/modules/{name}/__init__.py` | 模块初始化 |
| `models.py.tpl` | `src/modules/{name}/models.py` | ORM 模型 |
| `schemas.py.tpl` | `src/modules/{name}/schemas.py` | Pydantic 表单 |
| `repository.py.tpl` | `src/modules/{name}/repository.py` | 数据访问层 |
| `service.py.tpl` | `src/modules/{name}/service.py` | 业务逻辑层 |
| `endpoint.py.tpl` | `src/api/v1/endpoints/{name}.py` | HTTP 端点 |
### 前端文件(普通列表)
| 模板 | 输出路径 |
|:----|:----|
| `ui/index.vue.tpl` | `ui/src/views/tool/{name}/index.vue` |
| `ui/edit.vue.tpl` | `ui/src/views/tool/{name}/edit.vue` |
| `ui/detail.vue.tpl` | `ui/src/views/tool/{name}/detail.vue` |
| `ui/columns.ts.tpl` | `ui/src/views/tool/{name}/columns.ts` |
| `ui/querySchemas.ts.tpl` | `ui/src/views/tool/{name}/querySchemas.ts` |
| `ui/api.ts.tpl` | `ui/src/api/tool/{name}.ts` |
### 前端文件(树状列表)
| 模板 | 输出路径 |
|:----|:----|
| `ui2/index.vue.tpl` | `ui/src/views/tool/{name}/index.vue` |
| `ui2/edit.vue.tpl` | `ui/src/views/tool/{name}/edit.vue` |
| `ui2/detail.vue.tpl` | `ui/src/views/tool/{name}/detail.vue` |
| `ui/api.ts.tpl` | `ui/src/api/tool/{name}.ts` |
树状列表与普通列表共用 `api.ts.tpl`。
## 自动注册
### 路由注册
`_register_module()` 在 `src/api/v1/router.py` 中追加:
```python
# 导入语句(插入到最后一个 from api.v1.endpoints 导入之后)
from api.v1.endpoints.example import router as example_router
# 注册语句(追加到文件末尾)
v1.include_router(example_router, prefix="/example", tags=["案例"])
```
幂等操作:如果导入语句已存在,跳过。
### 菜单创建
`_create_menus()` 在数据库中创建:
1. **二级菜单**(type=0):页面路由
- name: 模块中文名
- path: `/tool/{module_camel}`
- component: `/tool/{module_camel}/index`
- parent_id: 189(开发工具)
2. **三级权限节点**(type=1)× 10 个:
| 权限 | 标识 |
|:----|:----|
| 分页查询 | `{prefix}:page` |
| 列表查询 | `{prefix}:list` |
| 详情查询 | `{prefix}:detail` |
| 新增 | `{prefix}:add` |
| 编辑 | `{prefix}:update` |
| 删除 | `{prefix}:delete` |
| 批量删除 | `{prefix}:batchDelete` |
| 状态管理 | `{prefix}:status` |
| 导入 | `{prefix}:import` |
| 导出 | `{prefix}:export` |
幂等操作:如果 path 已存在,跳过。创建后自动清除所有用户权限缓存。
## 总结
代码生成引擎根据数据库表结构和配置信息,通过 Jinja2 模板渲染生成后端(models/schemas/repository/service/endpoint)和前端(index.vue/edit.vue/columns.ts/querySchemas.ts/api.ts)全套代码,生成后自动注册路由和权限。
@@ -0,0 +1,317 @@
:::tip 本章概要
代码生成器 JSON 配置文件的格式说明,包括模块名称、字段属性、字典编码等配置项的详细解释。
:::
# 配置文件详解
代码生成器支持通过 JSON 配置文件驱动生成。配置文件可通过 CLI `--output` 导出,也可手动编写,然后用 `--config` 加载生成。
## 导出配置
```bash
# 从数据库表解析并导出
python generator.py fastapi_example --dry-run --output config.json
# 生成代码的同时保存配置
python generator.py fastapi_example --output config.json
```
## 使用配置生成
```bash
python generator.py --config config.json
```
跳过表解析,直接从配置文件读取生成参数。适用于:
- 微调字段配置后重新生成
- 表结构已不存在但配置保留
- 跨项目复用配置
## 配置文件结构
```json
{
"app_name": "example",
"module_comment": "案例",
"model_class_name": "Example",
"permission_prefix": "sys:example",
"display_field": "name",
"primary_key": "id",
"has_sort": true,
"has_status": true,
"has_unique_code": true,
"has_export": false,
"has_image_field": false,
"has_rich_text_field": true,
"fields": [...]
}
```
## 顶层配置项
| 字段 | 类型 | 必填 | 说明 |
|:----|:----|:----|:----|
| `app_name` | str | 是 | 模块名(小写下划线),用于目录名和文件名 |
| `module_comment` | str | 是 | 模块中文名,用于注释和菜单名 |
| `model_class_name` | str | 是 | 模型类名(帕斯卡命名) |
| `permission_prefix` | str | 否 | 权限前缀,默认 `sys:{app_name}` |
| `display_field` | str | 否 | 显示字段,默认 `name` |
| `primary_key` | str | 否 | 主键字段,默认 `id` |
| `has_sort` | bool | 否 | 有排序字段,默认 `false` |
| `has_status` | bool | 否 | 有状态字段,默认 `false` |
| `has_unique_code` | bool | 否 | 有唯一编码字段,默认 `false` |
| `has_export` | bool | 否 | 有导出功能,默认 `false` |
| `has_image_field` | bool | 否 | 有图片字段,默认 `false` |
| `has_rich_text_field` | bool | 否 | 有富文本字段,默认 `false` |
| `fields` | list | 是 | 字段配置列表 |
## 字段配置项
每个字段对象包含:
### 基础属性
| 字段 | 类型 | 必填 | 说明 |
|:----|:----|:----|:----|
| `name` | str | 是 | 字段名(snake_case) |
| `comment` | str | 否 | 字段注释 |
| `db_type` | str | 是 | SQLAlchemy 类型 |
| `db_args` | str | 否 | 类型参数(如 `"100"`) |
| `form_type` | str | 否 | Pydantic 类型(str/int/float/bool) |
| `max_length` | int | 否 | 最大长度 |
### 约束属性
| 字段 | 类型 | 默认值 | 说明 |
|:----|:----|:----|:----|
| `nullable` | bool | `false` | 是否可空 |
| `required` | bool | `true` | 是否必填(与 nullable 相反) |
| `default` | any | `null` | 默认值 |
### 展示控制
| 字段 | 类型 | 默认值 | 说明 |
|:----|:----|:----|:----|
| `in_form` | bool | `true` | 出现在表单中 |
| `in_list` | bool | `true` | 出现在列表中 |
| `editable` | bool | `true` | 可编辑 |
| `filterable` | bool | `false` | 作为查询条件 |
| `filter_type` | str | `模糊查询` | 筛选类型(`精确匹配`/`模糊查询`) |
| `searchable` | bool | `false` | 可搜索 |
### 功能标识
| 字段 | 类型 | 默认值 | 说明 |
|:----|:----|:----|:----|
| `is_image` | bool | `false` | 图片字段 |
| `is_rich_text` | bool | `false` | 富文本字段 |
| `is_status` | bool | `false` | 状态字段 |
| `is_sort` | bool | `false` | 排序字段 |
### 选项属性
| 字段 | 类型 | 说明 |
|:----|:----|:----|
| `choices` | list | `[[value, label], ...]` 元组列表 |
| `dict_code` | str | 数据字典编码 |
| `min_value` | int | 最小值 |
| `max_value` | int | 最大值 |
## 完整示例
```json
{
"app_name": "example",
"module_comment": "案例",
"model_class_name": "Example",
"permission_prefix": "sys:example",
"display_field": "name",
"has_sort": true,
"has_status": true,
"has_unique_code": true,
"has_image_field": true,
"has_rich_text_field": true,
"fields": [
{
"name": "name",
"comment": "案例名称",
"db_type": "String",
"db_args": "100",
"form_type": "str",
"max_length": 100,
"nullable": false,
"required": true,
"in_form": true,
"in_list": true,
"filterable": true,
"filter_type": "模糊查询",
"searchable": true
},
{
"name": "code",
"comment": "案例编码",
"db_type": "String",
"db_args": "50",
"form_type": "str",
"max_length": 50,
"nullable": false,
"required": true,
"in_form": true,
"in_list": true,
"filterable": true,
"filter_type": "精确匹配",
"searchable": true
},
{
"name": "type",
"comment": "案例类型:1-类型1 2-类型2 3-类型3",
"db_type": "Integer",
"form_type": "int",
"nullable": false,
"required": true,
"in_form": true,
"in_list": true,
"filterable": true,
"filter_type": "精确匹配",
"choices": [[1, "类型1"], [2, "类型2"], [3, "类型3"]],
"dict_code": "example_type"
},
{
"name": "status",
"comment": "案例状态:1-正常 2-停用",
"db_type": "Integer",
"form_type": "int",
"default": 1,
"nullable": false,
"required": true,
"in_form": true,
"in_list": true,
"filterable": true,
"filter_type": "精确匹配",
"is_status": true,
"choices": [[1, "正常"], [2, "停用"]],
"dict_code": "example_status"
},
{
"name": "sort",
"comment": "排序",
"db_type": "Integer",
"form_type": "int",
"default": 0,
"nullable": false,
"required": true,
"in_form": true,
"in_list": true,
"is_sort": true
},
{
"name": "cover",
"comment": "封面图",
"db_type": "String",
"db_args": "255",
"form_type": "str",
"max_length": 255,
"nullable": true,
"required": false,
"in_form": true,
"in_list": true,
"is_image": true
},
{
"name": "content",
"comment": "案例内容",
"db_type": "Text",
"form_type": "str",
"nullable": true,
"required": false,
"in_form": true,
"in_list": false,
"is_rich_text": true
},
{
"name": "remark",
"comment": "备注",
"db_type": "String",
"db_args": "500",
"form_type": "str",
"max_length": 500,
"nullable": true,
"required": false,
"in_form": true,
"in_list": true,
"filterable": true,
"filter_type": "模糊查询"
}
]
}
```
## 字段配置校验规则
`db_type` 必须是以下值之一:
| 合法值 | 对应 SQLAlchemy 类型 |
|:----|:----|
| `String` | String(需配合 `db_args` 指定长度) |
| `Text` | Text |
| `Integer` | Integer |
| `BigInteger` | BigInteger |
| `DateTime` | DateTime |
| `Date` | Date |
| `Time` | Time |
| `Float` | Float |
| `Numeric` | Numeric |
| `Boolean` | Boolean |
| `JSON` | JSON |
`form_type` 必须是以下值之一:`str` / `int` / `float` / `bool`
`filter_type` 必须是以下值之一:`精确匹配` / `模糊查询`
## 常用微调场景
### 修改模块中文名
```json
{
"module_comment": "培训记录"
}
```
### 隐藏字段(不出现在列表/表单)
```json
{
"name": "internal_code",
"in_form": false,
"in_list": false
}
```
### 添加自定义字段
在 `fields` 数组中追加新的字段配置。
### 修改筛选类型
```json
{
"name": "name",
"filterable": true,
"filter_type": "精确匹配"
}
```
### 添加选项
```json
{
"name": "level",
"choices": [[1, "初级"], [2, "中级"], [3, "高级"]],
"dict_code": "example_level"
}
```
## 总结
配置文件为 JSON 格式,包含模块名称、表名、字段属性、字典编码等信息。支持字段级别的精细配置(是否可搜索、是否在列表显示、字典编码映射等),可通过 Web UI 可视化编辑或手动修改 JSON 文件。
@@ -0,0 +1,358 @@
:::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. 进入案例管理页面,测试增删改查功能
![](/volume5/4.png)
## 生成代码逐文件解析
### 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 界面批量生成:
![](/volume5/3.png)
```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+ 行代码,涵盖后端三层 + 前端页面 + 路由注册 + 菜单权限。生成后根据业务需求进行微调即可投入使用。
@@ -0,0 +1,160 @@
:::tip 本章概要
代码生成器使用过程中常见问题的原因分析和解决方案。
:::
# 常见问题
## 生成报错 "模块 xxx 已存在"
**原因**:生成器会校验目标目录不存在,避免覆盖已有模块。
**解决方式**:
```bash
# 1. 删除已有模块目录
rm -rf src/modules/example
# 2. 删除已生成的端点文件
rm src/api/v1/endpoints/example.py
# 3. 从 router.py 中移除对应的导入和注册语句
# 删除这两行:
# from api.v1.endpoints.example import router as example_router
# v1.include_router(example_router, prefix="/example", tags=["案例"])
# 4. 删除数据库中对应的菜单记录
# DELETE FROM fastapi_menu WHERE path = '/tool/example';
# 5. 重新生成
python generator.py fastapi_example
```
## 生成后前端页面不显示
**排查步骤**:
1. **确认菜单已创建**:检查数据库 `fastapi_menu` 表中是否有 `path = '/tool/example'` 的记录
2. **确认路由组件路径**:菜单的 `component` 字段应为 `tool/example/index`
3. **确认权限已分配**:当前用户需要有对应菜单的访问权限
4. **清除缓存**:退出重新登录,或清除浏览器缓存
5. **确认后端已重启**:新路由需要重启后端服务才能生效
## 如何重新生成?
完整清理流程:
```bash
# 1. 删除后端模块
rm -rf src/modules/example
# 2. 删除端点
rm src/api/v1/endpoints/example.py
# 3. 清理 router.py 中的导入和注册
# 4. 删除前端文件
rm -rf ui/src/views/tool/example
rm ui/src/api/tool/example.ts
# 5. 删除数据库菜单
# DELETE FROM fastapi_menu WHERE path = '/tool/example';
# 6. 重新生成
python generator.py fastapi_example
```
## 批量生成有数量限制吗?
Web API 批量生成最多支持 50 个表(`MAX_BATCH_SIZE = 50`)。CLI 无限制,但建议逐表生成,便于排查问题。
## 树状列表是如何判断的?
当表中存在 `parent_id` 或 `pid` 字段时,自动切换为树状模板(`ui2/`),生成树形结构的增删改查页面。
树状列表与普通分页列表的区别:
| 维度 | 普通列表(ui/) | 树状列表(ui2/) |
|:----|:----|:----|
| 触发条件 | 无 parent_id/pid | 有 parent_id/pid |
| 模板数量 | 5 个组件 + 1 个 API | 3 个组件 + 1 个 API |
| 数据加载 | 分页请求 | 全量加载 + 前端 buildTree |
| 展开/折叠 | 无 | 支持 |
| 父子关系 | 无 | 自动识别 |
## CLI 报错 "No module named 'core'"
**原因**:未在项目根目录执行命令。
**解决**:确保在项目根目录(包含 `src/` 和 `generator.py` 的目录)执行:
```bash
cd /data/apps/djangoadmin
python generator.py fastapi_example
```
## 生成的代码有语法错误
**可能原因**:
- 表名或字段名包含特殊字符
- 字段注释包含未转义的引号
- 数据库连接异常导致解析不完整
**解决**:
1. 使用 `--dry-run` 检查解析结果
2. 导出配置文件检查字段内容:`python generator.py fastapi_example --dry-run --output config.json`
3. 手动修正配置文件后用 `--config` 重新生成
## 如何自定义生成的代码风格?
修改 `src/modules/generator/templates/` 下的模板文件。模板使用 Jinja2 语法,详见 [6.6 自定义模板](/zh/volume5/templates)。
修改模板后重新生成即可生效,不影响已有模块。
## 生成速度慢
**可能原因**:
- 数据库连接延迟高
- 表字段数量非常多(50+ 字段)
- 同时生成大量表(批量生成)
**解决**:
- 检查数据库网络连接
- 减少单次批量生成的表数量
- 使用 CLI 单表生成替代批量生成
## 生成器支持哪些数据库?
:::warning 数据库限制
代码生成器通过查询 MySQL 的 `information_schema` 获取表结构信息,**仅支持 MySQL 数据库**。`service.py` 中的 `_query_tables`、`_query_table_detail`、`_query_table_columns` 等函数使用了 MySQL 特有的 SQL 语法(如 `TABLE_SCHEMA = (SELECT DATABASE())`),在其他数据库中可能无法正常执行。
:::
代码生成器通过 `information_schema` 查询表元数据,支持以下数据库:
| 数据库 | 支持程度 |
|:----|:----|
| MySQL | 完全支持(主要开发和测试环境) |
| PostgreSQL | 支持(information_schema 兼容) |
| SQL Server | 支持(information_schema 兼容) |
| SQLite | 部分支持(information_schema 有限) |
| Oracle | 部分支持(需适配) |
## 模板语法错误如何排查?
**症状**:生成时报错 `jinja2.exceptions.TemplateSyntaxError`。
**排查步骤**:
1. 查看错误信息中的模板文件名和行号
2. 打开对应的 `.tpl` 文件检查语法
3. 常见错误:
- `{% if %}` 缺少 `{% endif %}`
- 变量名拼写错误(如 `f.nmae` 应为 `f.name`)
- 使用了未定义的变量(如字段对象中不存在的属性)
4. 修改模板后重新生成
## 总结
大部分问题可通过以下流程解决:
1. 使用 `--dry-run` 预览配置
2. 清理旧文件后重新生成
3. 确认数据库菜单和权限配置正确
4. 重启后端服务
@@ -0,0 +1,141 @@
:::tip 本章概要
代码生成器的整体架构、核心模块和生成流程概述。
:::
# 概述与架构
代码生成器是项目的核心效率工具,能够根据数据库表结构自动生成完整的后端三层模块代码和前端 Vue 页面代码,并自动注册路由和菜单权限节点。
## 生成能力总览
| 维度 | 生成内容 |
|:----|:----|
| 后端模块 | `__init__.py` / `models.py` / `schemas.py` / `repository.py` / `service.py` |
| 后端路由 | `api/v1/endpoints/{module}.py` + 自动注册到 `router.py` |
| 前端页面 | `index.vue` / `edit.vue` / `detail.vue` / `columns.ts` / `querySchemas.ts` / `api.ts` |
| 菜单权限 | 自动创建菜单节点 + 10 个权限节点 |
## 两种使用方式
| 方式 | 入口 | 适用场景 |
|:----|:----|:----|
| CLI 命令行 | `python generator.py <表名>` | 开发阶段,快速生成单个模块 |
| Web 管理界面 | 开发工具 → 代码生成 | 运维阶段,可视化操作,支持批量生成 |
两种方式共享同一套引擎代码(`src/modules/generator/`),生成结果完全一致。
## 文件结构
```
项目根目录
├── generator.py # CLI 命令行入口
└── src/modules/generator/
├── parser.py # 表结构解析器
├── code_generator.py # 代码生成引擎
├── service.py # Web API 业务逻辑
├── __init__.py
└── templates/ # Jinja2 模板目录
├── __init__.py.tpl # 模块初始化
├── models.py.tpl # ORM 模型
├── schemas.py.tpl # Pydantic 表单
├── repository.py.tpl # 数据访问层
├── service.py.tpl # 业务逻辑层
├── endpoint.py.tpl # HTTP 端点
├── ui/ # 普通分页列表模板(6 个)
│ ├── index.vue.tpl
│ ├── edit.vue.tpl
│ ├── detail.vue.tpl
│ ├── columns.ts.tpl
│ ├── querySchemas.ts.tpl
│ └── api.ts.tpl
└── ui2/ # 树状列表模板(3 个)
├── index.vue.tpl
├── edit.vue.tpl
└── detail.vue.tpl
```
## 核心组件
### parser.py — 表结构解析器
从 `information_schema` 读取表元数据,输出标准化配置字典。智能识别图片字段、富文本字段、状态字段、排序字段、枚举字段、查询条件等。
### code_generator.py — 代码生成引擎
接收配置字典,通过 Jinja2 渲染模板,写入文件,并自动注册路由和菜单权限。
### service.py — Web API 业务逻辑
提供表分页查询、表详情、字段查询、单表/批量生成等服务方法,供 HTTP 端点调用。
### templates/ — 模板目录
Jinja2 模板文件,分为后端模板(6 个)和前端模板(ui/ 6 个 + ui2/ 3 个)。含 `parent_id` / `pid` 字段的表自动切换为树形模板(ui2/)。
## 生成流程
```
┌─────────────────────────────────────┐
│ 数据库 information_schema │
└──────────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────┐
│ parser.py(表结构解析器) │
│ ─ 智能识别字段类型/图片/富文本/状态 │
│ ─ 生成标准化配置字典 │
└──────────────────┬──────────────────┘
│ 配置字典
▼
┌─────────────────────────────────────┐
│ code_generator.py(代码生成引擎) │
│ ─ normalize_config() 标准化 │
│ ─ Jinja2 模板渲染 │
└───┬──────────┬──────────┬──────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────┐
│ 后端模块 │ │ 前端页面 │ │ 自动注册 │
│ models │ │ index.vue│ │ router.py │
│ schemas │ │ edit.vue │ │ fastapi_menu │
│ repository│ │ columns │ │ 权限节点 │
│ service │ │ api.ts │ │ 清除缓存 │
│ endpoint │ │ ... │ │ │
└──────────┘ └──────────┘ └──────────────┘
```
## 使用限制
:::warning 使用前提
1. **数据库要求**:Web 管理界面的「代码生成」功能基于 MySQL 的 `information_schema` 查询表结构,仅支持 MySQL 数据库。CLI 命令行同样依赖 `information_schema`,需在 MySQL 环境下使用。
2. **表结构要求**:不支持复合主键、外键关联等复杂表结构,建议使用单主键(自增 id)的标准业务表。
3. **目录冲突**:生成前会校验目标模块目录不存在,已存在时需先手动删除。
:::
## 演示表
本章以 `fastapi_example` 表为贯穿案例:
```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='案例表';
```
## 总结
代码生成器通过解析数据库表结构,自动生成符合项目规范的完整模块代码。CLI 适合开发阶段快速生成,Web 界面适合运维阶段批量管理。模板使用 Jinja2 语法,可自由定制生成结果。
@@ -0,0 +1,246 @@
:::tip 本章概要
表结构解析引擎的工作原理,从数据库读取表元数据并智能推断字段用途的过程。
:::
# 表结构解析引擎
`src/modules/generator/parser.py` 是代码生成器的解析层,负责从数据库 `information_schema` 读取表元数据,输出标准化的配置字典。
## 核心类:TableSchemaParser
```python
from modules.generator.parser import TableSchemaParser
parser = TableSchemaParser("fastapi_example")
config = parser.parse()
```
### 构造参数
| 参数 | 说明 |
|:----|:----|
| `table_name` | 数据库表名,可带前缀(`fastapi_example`)或不带前缀(`example`) |
构造时自动处理:
- 保存原始表名(用于数据库查询)
- 去掉 `fastapi_` 前缀(用于生成代码命名)
- 初始化排除字段列表(`id` / `create_user` / `create_time` / `update_user` / `update_time` / `is_delete`)
## 解析流程
`parse()` 方法执行 9 步:
```
1. 获取表信息(TABLE_COMMENT、ENGINE 等)
2. 获取字段列表(排除系统字段)
3. 获取索引信息
4. 清理表名(去掉 fastapi_ 前缀)
5. 构建命名(app_name / module_comment / model_class_name)
6. 构建字段配置列表
7. 判断功能标识(has_sort / has_status / has_unique_code)
8. 获取显示字段(优先 name → title → 第一个字符串字段)
9. 组装完整配置字典
```
## 智能识别规则
### 图片字段
字段名包含以下关键词时,`is_image` 标记为 `True`:
```
avatar / cover / logo / image / photo / picture / img / icon / thumbnail / banner
```
效果:
- 前端表单生成图片上传组件
- 列表中显示图片预览
- Service 层自动处理文件迁移和 URL 补全
- 自动设置 `filterable=False`、`searchable=False`
### 富文本字段
`Text` 类型字段且注释包含以下关键词时,`is_rich_text` 标记为 `True`:
```
内容 / 介绍 / 说明 / 描述 / 详情 / 正文
```
效果:
- 前端表单生成富文本编辑器
- Service 层自动进行 XSS 清洗
### 状态字段
字段名包含以下关键词时,`is_status` 标记为 `True`:
```
status / state / is_active / is_enabled / is_deleted
```
效果:
- 自动生成状态切换接口(`/status`)
- 前端列表生成状态标签(启用/停用)
- `has_status_route=True`
### 排序字段
字段名包含以下关键词时,`is_sort` 标记为 `True`:
```
sort / order / seq / sequence / priority
```
效果:
- 分页查询默认按此字段排序
- `page_order_by` 自动配置
### 枚举字段
字段注释包含 `数字-文本` 格式(如 `1-正常 2-停用`)时,自动解析为选项列表:
```python
# 注释:"案例类型:1-类型1 2-类型2 3-类型3"
# 解析结果:
choices = [(1, '类型1'), (2, '类型2'), (3, '类型3')]
dict_code = 'example_type'
```
效果:
- 前端表单生成下拉选择框
- 列表中显示选项文本而非数字
- 自动设置 `filter_type='精确匹配'`
- 生成数据字典编码,用于 `serialize_maps`
### 查询条件
字段满足以下任一条件时,`filterable` 标记为 `True`:
1. 字段名包含关键词:`name` / `title` / `code` / `mobile` / `phone` / `email` / `username` / `type` / `category` / `status` / `dept_id` / `role_id` 等
2. 字段有数据库索引
3. 整数字段且有选项
查询类型判断:
- 字符串字段(非编码类)→ `模糊查询`(LIKE)
- 编码字段(code/sn/no)→ `精确匹配`(=)
- 整数字段 + 有选项 → `精确匹配`(=)
- 状态字段 → `精确匹配`(=)
## 字段类型映射
### 数据库 → SQLAlchemy
| 数据库类型 | SQLAlchemy 类型 |
|:----|:----|
| varchar / char | String |
| text / longtext / mediumtext / tinytext | Text |
| int / tinyint / smallint / mediumint | Integer |
| bigint | BigInteger |
| datetime / timestamp | DateTime |
| date | Date |
| time | Time |
| float / double / real | Float |
| decimal | Numeric |
| boolean / bit | Boolean |
| json | JSON |
### SQLAlchemy → Pydantic
| SQLAlchemy 类型 | Pydantic 类型 |
|:----|:----|
| String / Text | str |
| Integer / BigInteger | int |
| Float / Numeric | float |
| Boolean | bool |
| DateTime / Date / Time | str |
| JSON | str |
### SQLAlchemy → 中文显示
| SQLAlchemy 类型 | 中文 |
|:----|:----|
| String | 字符串 |
| Text | 长文本 |
| Integer | 整数 |
| BigInteger | 大整数 |
| DateTime | 日期时间 |
| Float | 浮点数 |
| Numeric | 小数 |
| Boolean | 布尔值 |
## 输出配置结构
`parse()` 返回的配置字典结构:
```python
{
"app_name": "example", # 模块名(去前缀小写)
"module_comment": "案例", # 模块中文名(表注释去掉"表"字)
"model_name": "example", # 模型名
"model_class_name": "Example", # 模型类名(帕斯卡命名)
"route_prefix": "example", # 路由前缀
"permission_prefix": "sys:example", # 权限前缀
"primary_key": "id", # 主键字段
"display_field": "name", # 显示字段
"display_field_camel": "name", # 显示字段驼峰
"table_name": "example", # 表名(去前缀)
"has_sort": True, # 有排序字段
"has_status": True, # 有状态字段
"has_unique_code": True, # 有唯一编码字段
"has_export": False, # 有导出功能
"has_image_field": False, # 有图片字段
"has_rich_text_field": True, # 有富文本字段
"fields": [ # 字段配置列表
{
"name": "name",
"camel_name": "name",
"comment": "案例名称",
"py_comment": "案例名称",
"db_type": "String",
"db_args": "100",
"form_type": "str",
"type_display": "字符串",
"max_length": 100,
"nullable": False,
"required": True,
"is_unique": False,
"db_index": False,
"default": None,
"default_repr": None,
"in_form": True,
"in_list": True,
"filterable": True,
"filter_type": "模糊查询",
"editable": True,
"searchable": True,
"is_image": False,
"is_rich_text": False,
"is_status": False,
"is_sort": False,
"choices": None,
"min_value": None,
"max_value": None,
},
# ... 更多字段
]
}
```
## 与 code_generator.py 的关系
```
parser.py code_generator.py
┌─────────────────────┐ ┌─────────────────────┐
│ TableSchemaParser │ │ CodeGenerator │
│ │ │ │
│ information_schema │ config │ Jinja2 模板渲染 │
│ ─────────────────> │ ───────> │ ─────────────────> │
│ 解析表结构 │ 字典 │ 生成文件 │
└─────────────────────┘ └─────────────────────┘
```
`parser.py` 负责"读",`code_generator.py` 负责"写",通过配置字典解耦。
## 总结
表结构解析引擎从数据库读取表和字段的元信息(类型、长度、注释、索引等),智能推断字段用途(是否可搜索、是否在列表显示、对应字典编码等),为代码生成器提供结构化的表描述数据。
@@ -0,0 +1,296 @@
:::tip 本章概要
代码生成器模板的 Jinja2 语法说明,包括模板变量、字段属性和自定义模板的开发方法。
:::
# 自定义模板
模板文件位于 `src/modules/generator/templates/`,使用 Jinja2 语法。修改模板后重新生成即可生效。
## 模板目录结构
```
templates/
├── __init__.py.tpl # 模块初始化
├── models.py.tpl # ORM 模型
├── schemas.py.tpl # Pydantic 表单
├── repository.py.tpl # 数据访问层
├── service.py.tpl # 业务逻辑层
├── endpoint.py.tpl # HTTP 端点
├── ui/ # 普通分页列表模板
│ ├── index.vue.tpl # 主页面
│ ├── edit.vue.tpl # 编辑弹窗
│ ├── detail.vue.tpl # 详情弹窗
│ ├── columns.ts.tpl # 表格列定义
│ ├── querySchemas.ts.tpl # 搜索表单 Schema
│ └── api.ts.tpl # API 请求封装
└── ui2/ # 树状列表模板
├── index.vue.tpl # 树形主页面
├── edit.vue.tpl # 树形编辑弹窗
└── detail.vue.tpl # 树形详情弹窗
```
## ui/ vs ui2/ 切换逻辑
当表中存在 `parent_id` 或 `pid` 字段时,自动切换为 `ui2/` 树形模板:
```
字段列表中是否有 parent_id / pid?
├── 是 → 使用 ui2/ 模板(3 个组件 + 1 个 API)
└── 否 → 使用 ui/ 模板(5 个组件 + 1 个 API)
```
两者共用 `ui/api.ts.tpl` 生成 API 接口文件。
## 模板变量
### 基础变量
| 变量 | 类型 | 说明 | 示例 |
|:----|:----|:----|:----|
| `app_name` | str | 模块名 | `example` |
| `module_comment` | str | 中文名 | `案例` |
| `module_comment_py` | str | 转义后中文名 | `案例` |
| `model_class_name` | str | 类名 | `Example` |
| `permission_prefix` | str | 权限前缀 | `sys:example` |
| `display_field` | str | 显示字段 | `name` |
| `sort_field` | str | 排序字段 | `sort` |
### 功能标识
| 变量 | 类型 | 说明 |
|:----|:----|:----|
| `has_sort` | bool | 有排序字段 |
| `has_status` | bool | 有状态字段 |
| `has_status_route` | bool | 生成状态路由 |
| `has_image_field` | bool | 有图片字段 |
| `has_rich_text_field` | bool | 有富文本字段 |
| `serialize_maps` | dict | 枚举映射 `{field_name: dict_code}` |
### 字段列表
| 变量 | 类型 | 说明 |
|:----|:----|:----|
| `fields` | list | 全部字段 |
| `form_fields` | list | 表单字段(`in_form=True`) |
| `filter_fields` | list | 精确匹配字段 |
| `like_fields` | list | 模糊查询字段 |
### 前端专用变量
| 变量 | 类型 | 说明 |
|:----|:----|:----|
| `module_name` | str | 驼峰模块名 |
| `model_class_name_camel` | str | 驼峰类名(首字母小写) |
| `list_fields` | list | 列表展示字段 |
| `searchable_fields` | list | 可搜索字段 |
| `editable_fields` | list | 可编辑字段 |
| `is_tree_structure` | bool | 是否树形结构 |
| `parent_id_field` | str | 父级字段名 |
| `route_prefix` | str | 路由前缀 |
| `api_path` | str | API 路径 |
| `has_search_form` | bool | 显示搜索表单 |
| `show_selection` | bool | 显示复选框 |
| `action_column_width` | int | 操作列宽度 |
## 字段对象属性
`fields` 列表中每个字段对象包含以下属性:
### 基础属性
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `name` | str | 字段名(snake_case) |
| `camel_name` | str | 驼峰字段名 |
| `comment` | str | 字段注释 |
| `py_comment` | str | 转义后注释(可嵌入 Python 字符串) |
| `label` | str | 清洗后的注释(去掉选项说明) |
### 类型属性
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `db_type` | str | SQLAlchemy 类型 |
| `db_args` | str | 类型参数(如 `"100"`) |
| `form_type` | str | Pydantic 类型 |
| `type_display` | str | 中文类型名 |
| `max_length` | int | 最大长度 |
### 约束属性
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `nullable` | bool | 是否可空 |
| `required` | bool | 是否必填 |
| `is_unique` | bool | 是否唯一 |
| `default` | any | 默认值 |
| `default_repr` | str | 默认值 Python 表示 |
### 功能标识
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `is_image` | bool | 图片字段 |
| `is_rich_text` | bool | 富文本字段 |
| `is_status` | bool | 状态字段 |
| `is_sort` | bool | 排序字段 |
### 展示控制
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `in_form` | bool | 出现在表单中 |
| `in_list` | bool | 出现在列表中 |
| `editable` | bool | 可编辑 |
| `filterable` | bool | 作为查询条件 |
| `filter_type` | str | 筛选类型 |
| `searchable` | bool | 可搜索 |
### 选项属性
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `choices` | list | `[(value, label), ...]` |
| `dict_code` | str | 数据字典编码 |
| `min_value` | int | 最小值 |
| `max_value` | int | 最大值 |
### 前端专用
| 属性 | 类型 | 说明 |
|:----|:----|:----|
| `purpose` | str | 用途说明 |
| `type` | str | 配置字段类型名(CharField/IntegerField/...) |
| `choices[].value` | any | 选项值 |
| `choices[].label` | str | 选项文本 |
| `choices[].type` | str | 标签颜色(success/danger/warning/info) |
## 自定义模板示例
### 示例 1:为所有字段添加索引
修改 `templates/models.py.tpl`:
```jinja2
{% if f.db_type == 'String' %}
{{ f.name }} = Column(String({{ f.db_args or 255 }}), nullable={{ 'True' if f.nullable else 'False' }}, index=True, comment="{{ f.comment }}")
{% endif %}
```
### 示例 2:自定义 Service 钩子
修改 `templates/service.py.tpl`,在 Service 类中添加钩子方法:
```jinja2
class {{ model_class_name }}Service(BaseService[{{ model_class_name }}]):
# ... 差异点声明 ...
{% if has_status %}
def _before_delete(self, ids) -> Optional[str]:
"""删除前校验:检查是否有关联数据"""
# TODO: 添加自定义校验逻辑
return None
{% endif %}
```
### 示例 3:自定义前端表格列宽
修改 `templates/ui/columns.ts.tpl`:
```jinja2
{% for f in list_fields %}
{
label: '{{ f.label }}',
prop: '{{ f.camel_name }}',
minWidth: {{ 80 + (f.max_length or 100) // 3 }}, {# 动态列宽 #}
},
{% endfor %}
```
## 新增模板
如需生成额外文件(如测试文件),按以下步骤操作:
### 第 1 步:创建模板文件
在 `templates/` 下新建 `test.py.tpl`:
```jinja2
# tests/test_{{ app_name }}.py
import pytest
from modules.{{ app_name }}.service import {{ app_name }}_service
class Test{{ model_class_name }}:
def test_get_page(self, client):
response = client.get("/api/v1/{{ app_name }}/page")
assert response.status_code == 200
```
### 第 2 步:注册到 BACKEND_TEMPLATES
在 `code_generator.py` 中添加:
```python
BACKEND_TEMPLATES = [
'__init__.py.tpl',
'models.py.tpl',
'schemas.py.tpl',
'repository.py.tpl',
'service.py.tpl',
'test.py.tpl', # 新增
]
```
### 第 3 步:调整输出路径(可选)
如果需要输出到非默认目录,修改 `generate()` 方法中的路径逻辑。
## Jinja2 语法速查
```jinja2
{# 注释 #}
{# 变量输出 #}
{{ app_name }}
{{ f.name | upper }}
{# 条件判断 #}
{% if has_status %}
# 有状态字段
{% elif has_sort %}
# 有排序字段
{% else %}
# 都没有
{% endif %}
{# 循环 #}
{% for f in fields %}
{{ f.name }}
{% endfor %}
{# 循环 + 条件过滤 #}
{% for f in fields if f.is_image %}
{{ f.name }}
{% endfor %}
{# 循环变量 #}
{% for f in fields %}
{{ loop.index }} {# 从 1 开始 #}
{{ loop.first }} {# 是否第一个 #}
{{ loop.last }} {# 是否最后一个 #}
{% endfor %}
{# 三元表达式 #}
{{ 'True' if f.nullable else 'False' }}
{# 字符串拼接 #}
{{ app_name }}_repo
{# 默认值 #}
{{ f.db_args or 255 }}
```
## 总结
模板使用 Jinja2 语法,每个模板对应一个生成文件。模板变量包括模块名、表名、字段列表等,字段属性包含名称、类型、注释、是否可搜索等。可通过修改模板自定义生成代码的风格和结构。
@@ -0,0 +1,142 @@
:::tip 本章概要
代码生成器 Web 管理界面的使用方法,通过可视化界面操作单表生成和批量生成。
:::
# Web 管理界面
登录管理后台,进入「开发工具 → 代码生成」页面,可通过可视化界面操作代码生成。
![](/demo/27.png)
:::warning 数据库要求
代码生成器的 Web 界面通过查询 MySQL 的 `information_schema` 获取表结构信息,**仅支持 MySQL 数据库**。如使用 PostgreSQL / SQL Server / SQLite 等其他数据库,请使用 CLI 命令行方式生成(需自行适配查询语句)。
:::
## 操作流程
完整操作流程:
```
1. 登录管理后台
2. 左侧菜单 → 开发工具 → 代码生成
3. 在表列表中搜索目标表(支持表名/表注释模糊搜索)
4. 点击表名可查看字段详情(字段名、类型、注释、是否可空等)
5. 单表生成:点击行末「生成」按钮
批量生成:勾选多表 → 点击「批量生成」按钮
6. 生成成功后,左侧菜单自动出现新模块入口
7. 进入新模块页面,测试增删改查功能
```
## 单表生成
1. 在表列表中搜索目标表(支持表名和表注释模糊搜索)
2. 点击目标表行的「生成」按钮
3. 系统自动解析表结构并生成全部代码
4. 生成完成后提示成功
![](/volume5/2.png)
## 批量生成
1. 勾选多个表(左侧复选框)
2. 点击表格上方的「批量生成」按钮
3. 系统逐表生成,完成后提示成功数量
![](/volume5/3.png)
批量生成限制:最多 50 个表(`MAX_BATCH_SIZE = 50`)。
## API 接口
Web 界面底层调用以下 API 接口:
### 查询表分页
```
GET /api/v1/generator/page?pageNo=1&pageSize=10&tableName=example
```
返回数据库表的分页数据,支持按表名和表注释模糊搜索。
### 查询表详情
```
GET /api/v1/generator/detail/{table_name}
```
返回单个表的元数据(表名、注释、引擎、行数、字符集等)。
### 查询表字段
```
GET /api/v1/generator/columns/{table_name}
```
返回表的字段列表(字段名、类型、注释、是否可空、默认值等)。
### 代码生成
```
POST /api/v1/generator/generate
```
请求体:
```json
{
"tableNames": [
"fastapi_example|案例表",
"fastapi_product|商品表"
]
}
```
`tableNames` 支持三种格式:
| 格式 | 示例 | 说明 |
|:----|:----|:----|
| 管道分隔 | `"fastapi_example\|案例表"` | 表名\|注释,注释覆盖数据库表注释 |
| 纯表名 | `"fastapi_example"` | 注释从数据库读取 |
| 字典 | `{"name": "fastapi_example", "comment": "案例表"}` | 结构化格式 |
成功返回:
```json
{
"code": 0,
"msg": "本次共计生成2个模块",
"data": 2
}
```
### 批量生成
```
POST /api/v1/generator/batchGenerate
```
请求体和返回格式与「代码生成」接口完全一致。
## 权限节点
| 权限标识 | 说明 |
|:----|:----|
| `sys:generator:page` | 查询表分页 |
| `sys:generator:detail` | 查询表详情/字段 |
| `sys:generator:generate` | 代码生成 |
| `sys:generator:batchGenerate` | 批量生成 |
## 与 CLI 的对比
| 维度 | CLI | Web 界面 |
|:----|:----|:----|
| 入口 | `python generator.py <表名>` | 开发工具 → 代码生成 |
| 适用场景 | 开发阶段,快速生成 | 运维阶段,可视化操作 |
| 批量生成 | 不支持(循环调用) | 支持(勾选多表) |
| 配置微调 | `--output` 导出 → 编辑 → `--config` 导入 | 不支持(直接生成) |
| 生成结果 | 完全一致 | 完全一致 |
| 预览模式 | `--dry-run` | 不支持 |
## 总结
Web 管理界面提供可视化的代码生成操作,支持单表生成和批量生成。通过选择数据库表、配置生成选项、预览生成文件,一键生成前后端全套代码并自动注册路由和权限。