Skill: jpzhengcn/django-vue-admin (version 1.0.0)

# django-vue-admin 代码生成器 一键生成完整的 django-vue-admin 风格项目代码。 ## 功能 用户告诉 Skill 要创建的模块，Skill 自动生成： - Django Model - Django Serializer - Django ViewSet - Django URL - Vue 页面 - Vue API ## 自动读取模板文档 Skill 内置以下模板文档，会自动读取用于代码生成： | 文档 | 用途 | |------|------| | `templates/CORE_MODULES.md` | 核心模块完整代码（用户/角色/组织/权限/字典/文件） | | `templates/BUSINESS_LOGIC.md` | 业务逻辑参考（用户/权限/工作流） | | `templates/LOGIC_FLOW.md` | 流程逻辑（登录/权限校验/数据权限） | | `templates/FIELD_TEMPLATE.md` | 字段模板（常用字段组合） | **Skill 会根据用户描述的模块，自动：** 1. 读取 FIELD_TEMPLATE.md 获取字段定义 2. 读取 BUSINESS_LOGIC.md 获取业务逻辑模式 3. 读取 LOGIC_FLOW.md 获取流程逻辑 4. 生成完整的 CRUD 代码 --- # 使用方式 ## 示例对话 **用户**: 创建一个产品管理模块，包含名称、价格、库存、分类字段 **Skill**: 自动生成以下代码： ```python # apps/product/models.py class Product(CommonBModel): name = models.CharField('产品名称', max_length=200) price = models.DecimalField('价格', max_digits=10, decimal_places=2) stock = models.IntegerField('库存', default=0) category = models.ForeignKey('Category', on_delete=models.CASCADE, verbose_name='分类') status = models.BooleanField('状态', default=True) ... ``` 用户直接复制到项目中即可使用。 --- # 代码生成器 ## 内置模板 ### 1. Model 模板 ```python from django.db import models from utils.model import CommonBModel class Product(CommonBModel): """产品""" name = models.CharField('产品名称', max_length=200) code = models.CharField('产品编码', max_length=50, unique=True) price = models.DecimalField('价格', max_digits=10, decimal_places=2) stock = models.IntegerField('库存', default=0) status = models.BooleanField('状态', default=True) description = models.TextField('描述', blank=True) # 关联字段 category = models.ForeignKey('Category', on_delete=models.CASCADE, verbose_name='分类', related_name='products') class Meta: verbose_name = '产品' verbose_name_plural = '产品' ordering = ['-create_time'] def __str__(self): return self.name ``` ### 2. Serializer 模板 ```python from rest_framework import serializers from .models import Product class ProductSerializer(serializers.ModelSerializer): category_name = serializers.CharField(source='category.name', read_only=True) class Meta: model = Product fields = '__all__' @staticmethod def setup_eager_loading(queryset): return queryset.select_related('category', 'create_by', 'belong_dept') class ProductCreateSerializer(serializers.ModelSerializer): class Meta: model = Product fields = ['name', 'code', 'category', 'price', 'stock', 'status', 'description'] ``` ### 3. ViewSet 模板 ```python from rest_framework.viewsets import ModelViewSet from rest_framework.permissions import IsAuthenticated from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter, OrderingFilter from .models import Product from .serializers import ProductSerializer, ProductCreateSerializer from utils.permission import RbacPermission class ProductViewSet(ModelViewSet): """产品管理""" perms_map = { 'get': '*', 'post': 'product_create', 'put': 'product_update', 'delete': 'product_delete', } permission_classes = [IsAuthenticated, RbacPermission] queryset = Product.objects.all() filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter] search_fields = ['name', 'code'] filterset_fields = ['category', 'status'] ordering = ['-create_time'] def get_serializer_class(self): if self.action in ['list', 'retrieve']: return ProductSerializer return ProductCreateSerializer def get_queryset(self): from utils.queryset import get_data_scope return get_data_scope(self.request.user, super().get_queryset()) ``` ### 4. URL 模板 ```python from rest_framework.routers import DefaultRouter from .views import ProductViewSet router = DefaultRouter() router.register(r'product', ProductViewSet, basename='product') urlpatterns = router.urls ``` ### 5. Vue API 模板 ```javascript export function getProductList(params) { return request({ url: '/myapp/product/', method: 'get', params }) } export function getProduct(id) { return request({ url: `/myapp/product/${id}/`, method: 'get' }) } export function createProduct(data) { return request({ url: '/myapp/product/', method: 'post', data }) } export function updateProduct(id, data) { return request({ url: `/myapp/product/${id}/`, method: 'put', data }) } export function deleteProduct(id) { return request({ url: `/myapp/product/${id}/`, method: 'delete' }) } ``` ### 6. Vue 页面模板 ```vue <template> <div class="app-container"> <div class="filter-container"> <el-input v-model="listQuery.name" placeholder="名称" style="width: 200px" @keyup.enter.native="handleFilter" /> <el-button type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button> <el-button type="primary" icon="el-icon-plus" @click="handleCreate" v-permission="['product_create']">新增</el-button> </div> <el-table v-loading="listLoading" :data="list" border stripe> <el-table-column prop="id" label="ID" width="80" /> <el-table-column prop="name" label="名称" /> <el-table-column prop="price" label="价格" width="100"> <template slot-scope="{row}">¥{{ row.price }}</template> </el-table-column> <el-table-column prop="stock" label="库存" width="80" /> <el-table-column prop="status" label="状态" width="80"> <template slot-scope="{row}"> <el-tag :type="row.status ? 'success' : 'danger'">{{ row.status ? '启用' : '禁用' }}</el-tag> </template> </el-table-column> <el-table-column label="操作" width="180" fixed="right"> <template slot-scope="{row}"> <el-button type="text" @click="handleUpdate(row)" v-permission="['product_update']">编辑</el-button> <el-button type="text" @click="handleDelete(row)" v-permission="['product_delete']">删除</el-button> </template> </el-table-column> </el-table> <pagination v-show="total>0" :total="total" :page.sync="listQuery.page" :limit.sync="listQuery.limit" @pagination="getList" /> <el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="600px"> <el-form ref="dataForm" :model="temp" :rules="rules" label-width="100px"> <el-form-item label="名称" prop="name"> <el-input v-model="temp.name" /> </el-form-item> <el-form-item label="价格" prop="price"> <el-input-number v-model="temp.price" :min="0" :precision="2" /> </el-form-item> <el-form-item label="库存"> <el-input-number v-model="temp.stock" :min="0" /> </el-form-item> <el-form-item label="状态"> <el-switch v-model="temp.status" /> </el-form-item> </el-form> <div slot="footer"> <el-button @click="dialogFormVisible = false">取消</el-button> <el-button type="primary" @click="dialogStatus==='create'?createData():updateData()">确定</el-button> </div> </el-dialog> </div> </template> <script> import Pagination from '@/components/Pagination' import { getProductList, createProduct, updateProduct, deleteProduct } from '@/api/myapp' export default { components: { Pagination }, data() { return { list: [], total: 0, listLoading: true, listQuery: { page: 1, limit: 20, name: '' }, dialogFormVisible: false, dialogStatus: '', textMap: { update: '编辑', create: '新增' }, temp: { id: undefined, name: '', price: 0, stock: 0, status: true }, rules: { name: [{ required: true, message: '必填', trigger: 'blur' }] } } }, created() { this.getList() }, methods: { getList() { this.listLoading = true getProductList(this.listQuery).then(res => { this.list = res.results || res this.total = res.count || this.list.length this.listLoading = false }) }, handleFilter() { this.listQuery.page = 1; this.getList() }, handleCreate() { this.temp = { id: undefined, name: '', price: 0, stock: 0, status: true } this.dialogStatus = 'create' this.dialogFormVisible = true }, handleUpdate(row) { this.temp = Object.assign({}, row) this.dialogStatus = 'update' this.dialogFormVisible = true }, createData() { this.$refs.dataForm.validate(valid => { if (valid) { createProduct(this.temp).then(() => { this.dialogFormVisible = false; this.getList() }) } }) }, updateData() { this.$refs.dataForm.validate(valid => { if (valid) { updateProduct(this.temp.id, this.temp).then(() => { this.dialogFormVisible = false; this.getList() }) } }) }, handleDelete(row) { this.$confirm('确认删除?').then(() => { deleteProduct(row.id).then(() => this.getList()) }) } } } </script> ``` --- # 字段类型映射 ## Django → Vue | Django 字段 | Vue 组件 | |------------|----------| | CharField | el-input | | TextField | el-input (type=textarea) | | IntegerField | el-input-number | | DecimalField | el-input-number | | BooleanField | el-switch | | ForeignKey | el-select | | DateField | el-date-picker | | DateTimeField | el-date-picker (type=datetime) | | ImageField | el-upload | | FileField | el-upload | --- # 生成流程 当用户说"创建一个产品模块"时： 1. **解析需求** - 模块名: Product - 字段: name, price, stock, status 2. **生成后端代码** - apps/myapp/models.py - apps/myapp/serializers.py - apps/myapp/views.py - apps/myapp/urls.py 3. **生成前端代码** - src/api/myapp.js - src/views/myapp/product.vue 4. **输出代码** - 用户直接复制使用 --- # 快速参考 ## 常用字段 ```python # 基础 name = models.CharField('名称', max_length=100) code = models.CharField('编码', max_length=50, unique=True) description = models.TextField('描述', blank=True) status = models.BooleanField('状态', default=True) sort = models.IntegerField('排序', default=0) # 数值 price = models.DecimalField('价格', max_digits=10, decimal_places=2) quantity = models.IntegerField('数量', default=0) # 关联 category = models.ForeignKey('Category', on_delete=models.CASCADE, verbose_name='分类') user = models.ForeignKey('system.User', on_delete=models.SET_NULL, null=True, verbose_name='用户') # 文件 image = models.ImageField('图片', upload_to='images/', null=True, blank=True) file = models.FileField('附件', upload_to='files/', null=True, blank=True) # 时间 start_date = models.DateField('开始日期', null=True, blank=True) expire_time = models.DateTimeField('过期时间', null=True, blank=True) ``` ## 项目启动 ```bash # 克隆 git clone https://github.com/caoqianming/django-vue-admin.git myproject cd myproject/server # 环境 python -m venv venv source venv/bin/activate pip install -r requirements.txt # 配置 cp server/conf_e.py server/conf.py # 数据库 python manage.py migrate python manage.py loaddata db.json # 运行 python manage.py runserver 0.0.0.0:8000 # 前端 cd ../client npm install npm run dev ```

path: templates/BUSINESS_LOGIC.md
content: # django-vue-admin 业务逻辑分析

## 一、模块总览

| 模块 | 说明 | 状态 |
|------|------|------|
| system | 系统管理 | ✅ 完整 |
| wf | 工作流引擎 | ✅ 完整 |
| crm | 客户管理 | ⚪ 空模块 |
| monitor | 系统监控 | ✅ 基础功能 |

---

## 二、system 模块 - 系统管理

### 2.1 功能清单

| 功能 | API 路径 | 权限代码 | 说明 |
|------|---------|---------|------|
| 用户管理 | /system/user/ | user_create/update/delete | 增删改查、密码修改、重置 |
| 角色管理 | /system/role/ | role_create/update/delete | 角色CRUD、权限分配 |
| 权限管理 | /system/perm/ | perm_create/update/delete | 目录/菜单/接口权限 |
| 组织管理 | /system/org/ | org_create/update/delete | 公司/部门架构 |
| 岗位管理 | /system/position/ | position_create/update/delete | 职位管理 |
| 字典类型 | /system/dicttype/ | dicttype_create/update/delete | 字典分类 |
| 字典管理 | /system/dict/ | dict_create/update/delete | 键值对配置 |
| 文件管理 | /system/file/ | - | 上传/下载/预览 |
| 定时任务 | /system/task/ | ptask_create/update/delete | Celery 任务管理 |
| 用户信息 | /system/user/info/ | - | 获取当前用户权限 |
| 修改密码 | /system/user/password/ | - | 修改登录密码 |

### 2.2 核心业务逻辑

#### 用户管理
```python
# 创建用户
- 默认密码: 0000
- 支持指定密码
- 支持多角色分配
- 支持部门归属

# 修改密码
- 验证旧密码
- 两次输入新密码一致
- 自动加密存储
```

#### 角色权限
```python
# 权限分配
- 功能权限: 菜单/接口级别的访问控制
- 数据权限: 全部/本级及以下/本级/仅本人

# 权限继承
- 用户 → 角色 → 权限 → 接口
```

#### 文件上传
```python
# 自动识别类型
- 图片 (image/*)
- 视频 (video/*)
- 音频 (audio/*)
- 文档 (application/*, text/*)

# 存储信息
- 文件名、大小、MIME类型
- 上传人、时间
```

#### 定时任务
```python
# 支持策略
- Interval: 间隔执行 (每N秒/分/时)
- Crontab: 定时执行 (Cron表达式)

# 任务管理
- 启用/禁用
- 立即执行
- 执行日志
```

---

## 三、wf 模块 - 工作流引擎

### 3.1 核心概念

```
Workflow (工作流定义)
    ↓
State (状态) ──── Transition (流转) ──── State (状态)
    ↓
Ticket (工单)
    ↓
TicketFlow (流转记录)
```

### 3.2 功能清单

| 功能 | API | 说明 |
|------|-----|------|
| 工作流管理 | /wf/workflow/ | 创建/配置工作流 |
| 状态管理 | /wf/state/ | 定义流程节点 |
| 流转管理 | /wf/transition/ | 定义流转规则 |
| 字段管理 | /wf/customfield/ | 自定义表单字段 |
| 工单管理 | /wf/ticket/ | 工单 CRUD |
| 流转记录 | /wf/flow/ | 查看处理历史 |
| 创建工单 | /wf/ticket/create/ | 提交流程 |
| 处理工单 | /wf/ticket/handle/ | 审批/处理 |
| 流转工单 | /wf/ticket/transition/ | 状态流转 |
| 转交 | /wf/ticket/deliver/ | 转交他人处理 |
| 加签 | /wf/ticket/add_node/ | 临时加签 |
| 退回 | /wf/ticket/retreat/ | 退回上一步 |
| 关闭 | /wf/ticket/close/ | 强制关闭 |

### 3.3 状态类型

```python
# 状态类型
type = (
    (0, '普通'),     # 普通处理节点
    (1, '开始'),     # 流程起点
    (2, '结束'),     # 流程终点
)

# 处理人类型
participant_type = (
    (0, '无处理人'),
    (1, '个人'),     # 指定用户
    (2, '多人'),     # 多人处理
    (3, '部门'),     # 部门成员
    (4, '角色'),     # 角色成员
    (5, '变量'),     # create_by (创建人)
    (6, '脚本'),     # Python 脚本
    (7, '工单字段'), # 从表单字段获取
)

# 分配方式
distribute_type = (
    (1, '主动接单'),  # 需要先接单
    (2, '直接处理'),  # 直接处理
    (3, '随机分配'),  # 随机分配
    (4, '全部处理'),  # 全部处理完才能流转
)
```

### 3.4 核心业务逻辑

#### 工单创建流程
```python
1. 获取工作流初始状态
2. 获取可用的流转规则
3. 获取自定义字段配置
4. 提交工单数据
5. 自动生成流水号 (sn)
6. 记录创建人、所属部门
```

#### 工单处理流程
```python
1. 验证处理人权限
2. 检查必填字段
3. 执行前置脚本 (Hook)
4. 记录处理意见
5. 流转到下一状态
6. 通知下一处理人
7. 更新工单状态
```

#### 特殊操作
```python
# 转交 (deliver)
- 当前处理人转交给其他人
- 保留转交记录

# 加签 (add_node)
- 临时添加处理人
- 加签完成后回到原处理人

# 退回 (retreat)
- 退回到上一步骤
- 需要填写退回原因

# 关闭 (close)
- 强制结束流程
- 仅管理员可操作
```

### 3.5 自定义字段

```python
# 支持的字段类型
field_type = (
    ('string', '字符串'),
    ('int', '整型'),
    ('float', '浮点'),
    ('boolean', '布尔'),
    ('date', '日期'),
    ('datetime', '日期时间'),
    ('radio', '单选'),
    ('checkbox', '多选'),
    ('select', '单选下拉'),
    ('selects', '多选下拉'),
    ('cascader', '级联'),
    ('textarea', '文本域'),
    ('file', '附件'),
)

# 字段属性
field_attribute = (
    (1, '只读'),
    (2, '必填'),
    (3, '可选'),
    (4, '隐藏'),
)
```

---

## 四、monitor 模块 - 系统监控

### 4.1 功能清单

| 功能 | API | 说明 |
|------|-----|------|
| 服务器信息 | /monitor/server/ | CPU/内存/磁盘 |
| 日志列表 | /monitor/log/ | 日志文件列表 |
| 日志详情 | /monitor/log/detail/ | 查看日志内容 |

### 4.2 服务器监控

```python
# CPU 信息
- 核心数 (物理/逻辑)
- 使用率

# 内存信息
- 总容量 (GB)
- 已使用 (GB)
- 使用率 (%)

# 磁盘信息
- 总容量 (GB)
- 已使用 (GB)
- 使用率 (%)
```

### 4.3 日志管理

```python
# 功能
- 列出日志文件 (按修改时间排序)
- 查看日志内容
- 文件大小显示

# 配置
LOG_PATH = 'logs/'  # 日志目录
```

---

## 五、crm 模块 - 客户管理

**状态**: 空模块，可基于此框架扩展

### 扩展建议

```python
# 可添加的模型
class Customer(CommonBModel):
    name = models.CharField('客户名称')
    industry = models.CharField('行业')
    level = models.CharField('客户等级')
    source = models.CharField('客户来源')
    ...

class Contact(CommonBModel):
    customer = models.ForeignKey(Customer)
    name = models.CharField('联系人')
    phone = models.CharField('电话')
    email = models.EmailField('邮箱')
    ...
```

---

## 六、权限体系详解

### 6.1 权限模型

```
用户 (User)
    ↓ 多个角色
角色 (Role)
    ├─ 功能权限 (perms) → Permission
    └─ 数据权限 (datas) → Organization
```

#### Permission (功能权限)
```python
class Permission(SoftModel):
    name = models.CharField('名称', max_length=30)      # "用户管理"
    type = models.CharField('类型', choices=           # 菜单/接口
        ('目录', '目录'),                               # 左侧菜单一级
        ('菜单', '菜单'),                               # 左侧菜单二级
        ('接口', '接口'))                               # API 权限
    method = models.CharField('方法/代号')              # 如: user_create
    parent = models.ForeignKey('self')                  # 父级权限
    sort = models.IntegerField('排序')                  # 菜单顺序
    is_frame = models.BooleanField('外部链接')           # 是否 iframe 加载
```

#### Role (角色)
```python
class Role(SoftModel):
    name = models.CharField('角色名')                  # "管理员"
    perms = models.ManyToManyField(Permission)        # 功能权限集合
    datas = models.CharField('数据权限', choices=      # 数据范围
        ('全部', '全部'),                               # 看所有数据
        ('自定义', '自定义'),                           # 看指定部门
        ('同级及以下', '同级及以下'),                     # 部门及同级
        ('本级及以下', '本级及以下'),                     # 本部门及子部门
        ('本级', '本级'),                               # 仅本部门
        ('仅本人', '仅本人'))                           # 仅自己创建
    depts = models.ManyToManyField(Organization)       # 自定义部门范围
```

### 6.2 功能权限 (菜单权限)

```python
# 权限类型
1. 目录 (Directory)     → 左侧菜单一级
2. 菜单 (Menu)          → 左侧菜单二级，可绑定权限
3. 接口 (Interface)     → API 权限代码

# 前端使用
v-permission="['user_create']"  # 按钮级控制
```

### 6.3 数据权限 (行级控制)

| 数据范围 | 说明 | SQL 逻辑 |
|---------|------|----------|
| 全部 | 所有数据 | 不过滤 |
| 自定义 | 指定部门 | belong_dept IN (指定部门) |
| 同级及以下 | 当前部门 + 同级部门 + 子部门 | belong_dept IN (同级及子部门) |
| 本级及以下 | 本部门 + 子部门 | belong_dept IN (子部门) |
| 本级 | 仅本部门 | belong_dept = 当前部门 |
| 仅本人 | 自己创建的数据 | create_by = 当前用户 |

### 6.4 权限校验流程

```
请求 → RbacPermission.has_permission()
    ├─ 超级管理员 → 直接放行
    ├─ 有 admin 权限 → 放行
    ├─ 无 perms_map 配置 → 放行
    └─ 校验接口权限
        └─ perms_map[method] ∈ user.perms → 放行

对象级 → has_object_permission()
    └─ 校验 belong_dept ∈ user.data_scope
```

### 6.5 完整权限架构图

```
┌─────────────────────────────────────────────────────┐
│                     用户 User                        │
│  username, name, phone, avatar, dept, roles        │
└─────────────────────┬───────────────────────────────┘
                      │ n:m
                      ▼
┌─────────────────────────────────────────────────────┐
│                     角色 Role                        │
│  name, perms(M), datas, depts(M), description     │
│                                                     │
│  数据权限:                                          │
│  ┌─────────────────────────────────────────────┐   │
│  │ 全部 | 自定义 | 同级及以下 | 本级及以下 | 本级 | 仅本人 │
│  └─────────────────────────────────────────────┘   │
└─────────────────────┬───────────────────────────────┘
                      │ n:m
                      ▼
┌─────────────────────────────────────────────────────┐
│                 权限 Permission                      │
│  name, type, method, parent, sort, is_frame       │
│                                                     │
│  类型:                                              │
│  ┌─────────┬─────────┬────────────┐               │
│  │ 目录     │ 菜单    │ 接口        │               │
│  │ (一级菜单)│ (二级菜单)│ (API权限)   │               │
│  └─────────┴─────────┴────────────┘               │
└─────────────────────────────────────────────────────┘
```

### 6.6 前端权限控制

```vue
<!-- 1. 菜单权限 (路由守卫) -->
<el-menu>
  <el-menu-item v-if="hasPermission('user')">用户管理</el-menu-item>
</el-menu>

<!-- 2. 按钮权限 (指令) -->
<el-button v-permission="['user_create']">新增</el-button>
<el-button v-permission="['user_delete']">删除</el-button>

<!-- 3. API 权限 (后端自动校验) -->
<!-- perms_map = {'post': 'user_create'} -->
```

---

## 七、API 接口规范

### 7.1 响应格式

```json
// 成功
{
  "results": [...],
  "count": 100,
  "next": "...",
  "previous": null
}

// 详情
{
  "id": 1,
  "name": "xxx",
  ...
}

// 错误
{
  "detail": "错误信息"
}
```

### 7.2 分页参数

```
GET /api/xxx/?page=1&limit=20
```

---

## 八、扩展开发指南

### 8.1 新增业务模块

```python
# 1. 创建 App
python manage.py startapp myapp apps/

# 2. 定义模型
from utils.model import CommonBModel

class MyModel(CommonBModel):
    name = models.CharField('名称')
    ...

# 3. 创建序列化器
class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyModel
        fields = '__all__'

# 4. 创建视图
class MyModelViewSet(ModelViewSet):
    perms_map = {'get': '*', 'post': 'my_create', ...}
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

# 5. 注册路由
router.register(r'my', MyModelViewSet)
```

### 8.2 添加定时任务

```python
# 1. 创建任务
from celery import shared_task

@shared_task
def my_task():
    print('执行任务')

# 2. 后台配置
# settings.py 添加配置

# 3. 访问管理后台创建定时任务
```


path: templates/CORE_MODULES.md
content: # django-vue-admin 核心模块完整代码

基于 django-vue-admin 项目的完整实现，包含所有业务逻辑。

---

## 一、Model 定义

### 1.1 系统模型完整代码

```python
# apps/system/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from utils.model import SoftModel
from simple_history.models import HistoricalRecords


class Position(SoftModel):
    """岗位"""
    name = models.CharField('名称', max_length=32, unique=True)
    description = models.CharField('描述', max_length=50, blank=True, null=True)

    class Meta:
        verbose_name = '职位/岗位'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Permission(SoftModel):
    """功能权限:目录,菜单,接口"""
    menu_type_choices = (
        ('目录', '目录'),
        ('菜单', '菜单'),
        ('接口', '接口')
    )
    name = models.CharField('名称', max_length=30)
    type = models.CharField('类型', max_length=20, choices=menu_type_choices, default='接口')
    is_frame = models.BooleanField('外部链接', default=False)
    sort = models.IntegerField('排序标记', default=1)
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='父')
    method = models.CharField('方法/代号', max_length=50, null=True, blank=True)

    class Meta:
        verbose_name = '功能权限表'
        verbose_name_plural = verbose_name
        ordering = ['sort']

    def __str__(self):
        return self.name


class Organization(SoftModel):
    """组织架构"""
    organization_type_choices = (
        ('公司', '公司'),
        ('部门', '部门')
    )
    name = models.CharField('名称', max_length=60)
    type = models.CharField('类型', max_length=20, choices=organization_type_choices, default='部门')
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='父')

    class Meta:
        verbose_name = '组织架构'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Role(SoftModel):
    """角色"""
    data_type_choices = (
        ('全部', '全部'),
        ('自定义', '自定义'),
        ('同级及以下', '同级及以下'),
        ('本级及以下', '本级及以下'),
        ('本级', '本级'),
        ('仅本人', '仅本人')
    )
    name = models.CharField('角色', max_length=32, unique=True)
    perms = models.ManyToManyField(Permission, blank=True, verbose_name='功能权限')
    datas = models.CharField('数据权限', max_length=50, choices=data_type_choices, default='本级及以下')
    depts = models.ManyToManyField(Organization, blank=True, verbose_name='权限范围', related_name='roles')
    description = models.CharField('描述', max_length=50, blank=True, null=True)

    class Meta:
        verbose_name = '角色'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class User(AbstractUser):
    """用户"""
    name = models.CharField('姓名', max_length=20, null=True, blank=True)
    phone = models.CharField('手机号', max_length=11, null=True, blank=True, unique=True)
    avatar = models.CharField('头像', max_length=100, default='/media/default/avatar.png', null=True, blank=True)
    dept = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='组织')
    position = models.ManyToManyField(Position, blank=True, verbose_name='岗位')
    superior = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='上级主管')
    roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')

    class Meta:
        verbose_name = '用户信息'
        verbose_name_plural = verbose_name
        ordering = ['id']

    def __str__(self):
        return self.username


class DictType(SoftModel):
    """数据字典类型"""
    name = models.CharField('名称', max_length=30)
    code = models.CharField('代号', max_length=30, unique=True)
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='父')

    class Meta:
        verbose_name = '字典类型'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Dict(SoftModel):
    """数据字典"""
    name = models.CharField('名称', max_length=60)
    code = models.CharField('编号', max_length=30, null=True, blank=True)
    description = models.TextField('描述', blank=True, null=True)
    type = models.ForeignKey(DictType, on_delete=models.CASCADE, verbose_name='类型')
    sort = models.IntegerField('排序', default=1)
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, verbose_name='父')
    is_used = models.BooleanField('是否有效', default=True)
    history = HistoricalRecords()

    class Meta:
        verbose_name = '字典'
        verbose_name_plural = verbose_name
        unique_together = ('name', 'is_used', 'type')

    def __str__(self):
        return self.name


class CommonAModel(SoftModel):
    """业务用基本表A - 包含创建人/更新人"""
    create_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, 
                                 verbose_name='创建人', related_name='%(class)s_create_by')
    update_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, 
                                 verbose_name='最后编辑人', related_name='%(class)s_update_by')

    class Meta:
        abstract = True


class CommonBModel(SoftModel):
    """业务用基本表B - 包含创建人/更新人/所属部门"""
    create_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, 
                                 verbose_name='创建人', related_name='%(class)s_create_by')
    update_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, 
                                 verbose_name='最后编辑人', related_name='%(class)s_update_by')
    belong_dept = models.ForeignKey(Organization, on_delete=models.SET_NULL, null=True, blank=True, 
                                   verbose_name='所属部门', related_name='%(class)s_belong_dept')

    class Meta:
        abstract = True


class File(CommonAModel):
    """文件存储表"""
    name = models.CharField('名称', max_length=100, null=True, blank=True)
    size = models.IntegerField('文件大小', default=1, null=True, blank=True)
    file = models.FileField('文件', upload_to='%Y/%m/%d/')
    type_choices = (
        ('文档', '文档'),
        ('视频', '视频'),
        ('音频', '音频'),
        ('图片', '图片'),
        ('其它', '其它')
    )
    mime = models.CharField('文件格式', max_length=120, null=True, blank=True)
    type = models.CharField('文件类型', max_length=50, choices=type_choices, default='文档')
    path = models.CharField('地址', max_length=200, null=True, blank=True)

    class Meta:
        verbose_name = '文件库'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name
```

---

## 二、权限校验类

### 2.1 功能权限校验

```python
# apps/system/permission.py
from django.core.cache import cache
from rest_framework.permissions import BasePermission
from utils.queryset import get_child_queryset2
from .models import Organization, Permission
from django.db.models import Q


def get_permission_list(user):
    """获取权限列表,可用redis存取"""
    if user.is_superuser:
        perms_list = ['admin']
    else:
        perms = Permission.objects.none()
        roles = user.roles.all()
        if roles:
            for i in roles:
                perms = perms | i.perms.all()
        perms_list = perms.values_list('method', flat=True)
        perms_list = list(set(perms_list))
    cache.set(user.username + '__perms', perms_list, 60*60)
    return perms_list


class RbacPermission(BasePermission):
    """基于角色的权限校验类"""

    def has_permission(self, request, view):
        if not request.user:
            perms = ['visitor']
        else:
            perms = cache.get(request.user.username + '__perms')
        if not perms:
            perms = get_permission_list(request.user)
        if perms:
            if 'admin' in perms:
                return True
            elif not hasattr(view, 'perms_map'):
                return True
            else:
                perms_map = view.perms_map
                _method = request._request.method.lower()
                if perms_map:
                    for key in perms_map:
                        if key == _method or key == '*':
                            if perms_map[key] in perms or perms_map[key] == '*':
                                return True
                return False
        else:
            return False
    
    def has_object_permission(self, request, view, obj):
        if not request.user:
            return False
        if hasattr(obj, 'belong_dept'):
            has_obj_perm(request.user, obj)
        return True


def has_obj_perm(user, obj):
    """数据权限控权"""
    roles = user.roles
    data_range = roles.values_list('datas', flat=True)
    if '全部' in data_range:
        return True
    elif '自定义' in data_range:
        depts = Organization.objects.filter(roles__in=roles)
        if obj.belong_dept not in depts:
            return False
    elif '同级及以下' in data_range:
        if user.dept.parent:
            belong_depts = get_child_queryset2(user.dept.parent)
            if obj.belong_dept not in belong_depts:
                return False
    elif '本级及以下' in data_range:
        belong_depts = get_child_queryset2(user.dept)
        if obj.belong_dept not in belong_depts:
            return False
    elif '本级' in data_range:
        if obj.belong_dept is not user.dept:
            return False
    return True
```

### 2.2 数据权限过滤器

```python
# apps/system/permission_data.py
from django.db.models import Q
from django.db.models.query import QuerySet
from rest_framework.generics import GenericAPIView
from apps.system.mixins import CreateUpdateModelBMixin
from apps.system.models import Organization
from utils.queryset import get_child_queryset2


class RbacFilterSet(CreateUpdateModelBMixin, object):
    """
    数据权限控权返回的queryset
    在必须的View下继承
    """
    def get_queryset(self):
        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            queryset = queryset.all()

        if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
            queryset = self.get_serializer_class().setup_eager_loading(queryset)
        
        if self.request.user.is_superuser:
            return queryset

        if hasattr(queryset.model, 'belong_dept'):
            user = self.request.user
            roles = user.roles
            data_range = roles.values_list('datas', flat=True)
            
            if '全部' in data_range:
                return queryset
            elif '自定义' in data_range:
                return queryset.filter(belong_dept__roles__in=roles)
            elif '同级及以下' in data_range:
                if user.dept.parent:
                    belong_depts = get_child_queryset2(user.dept.parent)
                    return queryset.filter(belong_dept__in=belong_depts)
            elif '本级及以下' in data_range:
                belong_depts = get_child_queryset2(user.dept)
                return queryset.filter(belong_dept__in=belong_depts)
            elif '本级' in data_range:
                return queryset.filter(belong_dept=user.dept)
            elif '仅本人' in data_range:
                return queryset.filter(Q(create_by=user) | Q(update_by=user))
        return queryset


def rbac_filter_queryset(user, queryset):
    """数据权限控权方法"""
    if user.is_superuser:
        return queryset

    roles = user.roles
    data_range = roles.values_list('datas', flat=True)
    
    if hasattr(queryset.model, 'belong_dept'):
        if '全部' in data_range:
            return queryset
        elif '自定义' in data_range:
            if roles.depts.exists():
                return queryset.filter(belong_dept__in=roles.depts)
        elif '同级及以下' in data_range:
            if user.dept.parent:
                belong_depts = get_child_queryset2(user.dept.parent)
                return queryset.filter(belong_dept__in=belong_depts)
        elif '本级及以下' in data_range:
            belong_depts = get_child_queryset2(user.dept)
            return queryset.filter(belong_dept__in=belong_depts)
        elif '本级' in data_range:
            return queryset.filter(belong_dept=user.dept)
        elif '仅本人' in data_range:
            return queryset.filter(Q(create_by=user) | Q(update_by=user))
    return queryset
```

---

## 三、认证后端

### 3.1 自定义认证 (支持用户名/手机/邮箱)

```python
# apps/system/authentication.py
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q
from django.contrib.auth import get_user_model

UserModel = get_user_model()


class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get(
                Q(username=username) | Q(phone=username) | Q(email=username))
        except UserModel.DoesNotExist:
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
```

---

## 四、信号处理

### 4.1 角色变更时自动更新权限缓存

```python
# apps/system/signals.py
from django.db.models.signals import m2m_changed
from .models import Role, Permission, User
from django.dispatch import receiver
from django.core.cache import cache
from .permission import get_permission_list


@receiver(m2m_changed, sender=User.roles.through)
def update_perms_cache_user(sender, instance, action, **kwargs):
    """变更用户角色时动态更新权限缓存"""
    if action in ['post_remove', 'post_add']:
        if cache.get(instance.username+'__perms', None):
            get_permission_list(instance)
```

---

## 五、ViewSet 完整实现

### 5.1 用户管理 ViewSet

```python
# apps/system/views.py - UserViewSet
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.filters import SearchFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import action
from rest_framework.response import Response
from django.contrib.auth.hashers import make_password, check_password
from django.core.exceptions import ValidationError

from .models import User, Organization
from .serializers import UserListSerializer, UserCreateSerializer, UserModifySerializer
from .filters import UserFilter
from .mixins import OptimizationMixin
from .permission import RbacPermission, get_permission_list


class UserViewSet(OptimizationMixin, ModelViewSet):
    """用户管理"""
    perms_map = {
        'get': '*',
        'post': 'user_create',
        'put': 'user_update',
        'delete': 'user_delete',
    }
    queryset = User.objects.all()
    serializer_class = UserListSerializer
    filterset_class = UserFilter
    search_fields = ['username', 'name', 'phone', 'email']
    ordering_fields = ['-id']

    def perform_destroy(self, instance):
        if instance.is_superuser:
            raise ValidationError('不能删除超级用户')
        instance.delete()

    def get_queryset(self):
        queryset = super().get_queryset()
        if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
            queryset = self.get_serializer_class().setup_eager_loading(queryset)
        # 按部门过滤
        dept = self.request.query_params.get('dept', None)
        if dept:
            from utils.queryset import get_child_queryset2
            deptqueryset = get_child_queryset2(Organization.objects.get(pk=dept))
            queryset = queryset.filter(dept__in=deptqueryset)
        return queryset

    def get_serializer_class(self):
        if self.action == 'create':
            return UserCreateSerializer
        elif self.action == 'update':
            return UserModifySerializer
        elif self.action == 'list':
            return UserListSerializer
        return super().get_serializer_class()

    def create(self, request, *args, **kwargs):
        [REDACTED_SECRET]'password', '0000')
        if [REDACTED_SECRET] = make_password(password)
        else:
            [REDACTED_SECRET]'0000')
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save([REDACTED_SECRET])
        return Response(serializer.data)

    @action(methods=['put'], detail=False, url_path='password')
    def password(self, request, pk=None):
        """修改密码"""
        user = request.user
        old_password = request.data.get('old_password')
        if check_password(old_password, user.password):
            new_password1 = request.data.get('new_password1')
            new_password2 = request.data.get('new_password2')
            if new_password1 == new_password2:
                user.set_password(new_password2)
                user.save()
                return Response('密码修改成功!')
            else:
                return Response('新密码两次输入不一致!', status=400)
        else:
            return Response('旧密码错误!', status=400)

    @action(methods=['get'], detail=False, url_path='info')
    def info(self, request, pk=None):
        """获取当前用户信息"""
        user = request.user
        perms = get_permission_list(user)
        return Response({
            'id': user.id,
            'username': user.username,
            'name': user.name,
            'roles': user.roles.values_list('name', flat=True),
            'avatar': user.avatar,
            'perms': perms,
        })
```

### 5.2 角色管理 ViewSet

```python
class RoleViewSet(OptimizationMixin, ModelViewSet):
    """角色管理"""
    perms_map = {
        'get': '*',
        'post': 'role_create',
        'put': 'role_update',
        'delete': 'role_delete',
    }
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    search_fields = ['name']
    ordering_fields = ['id']
```

---

## 六、Mixins

### 6.1 创建/更新自动填充

```python
# apps/system/mixins.py
from django.db.models.query import QuerySet


class CreateUpdateModelAMixin:
    """业务用基本表A用"""
    def perform_create(self, serializer):
        serializer.save(create_by=self.request.user)
    
    def perform_update(self, serializer):
        serializer.save(update_by=self.request.user)


class CreateUpdateModelBMixin:
    """业务用基本表B用"""
    def perform_create(self, serializer):
        serializer.save(create_by=self.request.user, belong_dept=self.request.user.dept)
    
    def perform_update(self, serializer):
        serializer.save(update_by=self.request.user)


class CreateUpdateCustomMixin:
    """整合版 - 自动判断"""
    def perform_create(self, serializer):
        if hasattr(self.queryset.model, 'belong_dept'):
            serializer.save(create_by=self.request.user, belong_dept=self.request.user.dept)
        else:
            serializer.save(create_by=self.request.user)
    
    def perform_update(self, serializer):
        serializer.save(update_by=self.request.user)


class OptimizationMixin:
    """性能优化 - eager loading"""
    def get_queryset(self):
        queryset = self.queryset
        if isinstance(queryset, QuerySet):
            queryset = queryset.all()
        if hasattr(self.get_serializer_class(), 'setup_eager_loading'):
            queryset = self.get_serializer_class().setup_eager_loading(queryset)
        return queryset
```

---

## 七、工具函数

### 7.1 部门层级获取

```python
# utils/queryset.py
from django.db import models
from django.apps import apps


def get_child_queryset2(obj, hasParent=True):
    """获取所有子部门"""
    cls = type(obj)
    queryset = cls.objects.none()
    fatherQueryset = cls.objects.filter(pk=obj.id)
    if hasParent:
        queryset = queryset | fatherQueryset
    child_queryset = cls.objects.filter(parent=obj)
    while child_queryset:
        queryset = queryset | child_queryset
        child_queryset = cls.objects.filter(parent__in=child_queryset)
    return queryset


def get_parent_queryset(obj, hasSelf=True):
    """获取所有上级部门"""
    cls = type(obj)
    ids = []
    if hasSelf:
        ids.append(obj.id)
    while obj.parent:
        obj = obj.parent
        ids.append(obj.id)
    return cls.objects.filter(id__in=ids)
```

---

## 八、过滤器

### 8.1 用户过滤器

```python
# apps/system/filters.py
from django_filters import rest_framework as filters
from .models import User


class UserFilter(filters.FilterSet):
    class Meta:
        model = User
        fields = {
            'name': ['exact', 'contains'],
            'is_active': ['exact'],
        }
```

---

## 九、初始权限数据

### 9.1 权限数据示例

```python
# 权限数据结构
permissions = [
    # 系统管理
    {'name': '系统管理', 'type': '目录', 'sort': 1},
    {'name': '用户管理', 'type': '菜单', 'parent': None, 'path': '/system/user', 'component': 'system/user'},
    {'name': '用户列表', 'type': '接口', 'method': 'user_list'},
    {'name': '用户创建', 'type': '接口', 'method': 'user_create'},
    {'name': '用户修改', 'type': '接口', 'method': 'user_update'},
    {'name': '用户删除', 'type': '接口', 'method': 'user_delete'},
    {'name': '角色管理', 'type': '菜单'},
    {'name': '组织管理', 'type': '菜单'},
    {'name': '权限管理', 'type': '菜单'},
    # 工作流
    {'name': '工作流', 'type': '目录', 'sort': 2},
    {'name': '工单管理', 'type': '菜单'},
    # 监控
    {'name': '系统监控', 'type': '目录', 'sort': 3},
]
```

---

## 十、配置

### 10.1 Django 设置

```python
# settings.py

# 认证后端
AUTHENTICATION_BACKENDS = [
    'apps.system.authentication.CustomBackend',
    'django.contrib.auth.backends.ModelBackend',
]

# JWT 配置
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(hours=12),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    'AUTH_HEADER_TYPES': ('Bearer',),
}

# 自定义用户模型
AUTH_USER_MODEL = 'system.User'
```

### 10.2 URL 配置

```python
# urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    # JWT
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    # 系统
    path('api/system/', include('apps.system.urls')),
]
```

---

## 十一、API 接口汇总

| 模块 | 接口 | 权限 | 说明 |
|------|------|------|------|
| 用户 | GET /api/system/user/ | * | 用户列表 |
| | POST /api/system/user/ | user_create | 创建用户 |
| | GET /api/system/user/{id}/ | * | 用户详情 |
| | PUT /api/system/user/{id}/ | user_update | 更新用户 |
| | DELETE /api/system/user/{id}/ | user_delete | 删除用户 |
| | GET /api/system/user/info/ | - | 当前用户信息 |
| | PUT /api/system/user/password/ | - | 修改密码 |
| 角色 | GET /api/system/role/ | * | 角色列表 |
| | POST /api/system/role/ | role_create | 创建角色 |
| 组织 | GET /api/system/organization/ | * | 组织列表 |
| 权限 | GET /api/system/permission/ | * | 权限列表 |
| 登录 | POST /api/token/ | - | 获取Token |
| | POST /api/token/refresh/ | - | 刷新Token |


path: templates/FIELD_TEMPLATE.md
content: # Django Model 字段模板 (基于 django-vue-admin 项目分析)

## 一、通用业务字段模板

### 1.1 基础业务模型 (CommonBModel)

适用于大多数业务表，包含完整的数据权限字段：

```python
from django.db import models
from utils.model import CommonBModel

class MyModel(CommonBModel):
    """
    业务模型 - 继承 CommonBModel
    包含: create_time, update_time, is_deleted, create_by, update_by, belong_dept
    """
    # ===== 业务字段 =====
    name = models.CharField('名称', max_length=100)
    code = models.CharField('编码', max_length=50, unique=True)
    status = models.BooleanField('状态', default=True)
    sort = models.IntegerField('排序', default=0)
    description = models.TextField('描述', blank=True)
    
    # ===== 关联字段 =====
    category = models.ForeignKey('Category', on_delete=models.CASCADE, 
                                verbose_name='分类', related_name='models')
    parent = models.ForeignKey('self', on_delete=models.CASCADE, 
                              null=True, blank=True, verbose_name='父级')
    
    # ===== 特殊字段 =====
    # 金额/数量
    price = models.DecimalField('价格', max_digits=10, decimal_places=2, default=0)
    quantity = models.IntegerField('数量', default=0)
    
    # 富文本/文件
    content = models.TextField('内容', blank=True)
    image = models.ImageField('图片', upload_to='images/', null=True, blank=True)
    file = models.FileField('附件', upload_to='files/', null=True, blank=True)
    
    # JSON 扩展
    extra = models.JSONField('扩展信息', default=dict, blank=True)
    
    class Meta:
        verbose_name = '业务名称'
        verbose_name_plural = verbose_name
        ordering = ['sort', '-create_time']
    
    def __str__(self):
        return self.name
```

### 1.2 简单业务模型 (CommonAModel)

适用于不需要部门数据权限的表：

```python
from utils.model import CommonAModel

class MyModel(CommonAModel):
    """简单业务模型 - 继承 CommonAModel"""
    name = models.CharField('名称', max_length=100)
    # 包含: create_time, update_time, is_deleted, create_by, update_by
```

---

## 二、字段类型速查表

### 2.1 常用字段

| 字段类型 | 用途 | 示例 |
|---------|------|------|
| CharField | 短文本 | `name = models.CharField('名称', max_length=100)` |
| TextField | 长文本 | `description = models.TextField('描述', blank=True)` |
| IntegerField | 整数 | `quantity = models.IntegerField('数量', default=0)` |
| DecimalField | 金额 | `price = models.DecimalField('价格', max_digits=10, decimal_places=2)` |
| BooleanField | 布尔 | `status = models.BooleanField('状态', default=True)` |
| DateField | 日期 | `start_date = models.DateField('开始日期', null=True, blank=True)` |
| DateTimeField | 日期时间 | `create_time = models.DateTimeField('创建时间', auto_now_add=True)` |
| JSONField | JSON 数据 | `extra = models.JSONField('扩展', default=dict, blank=True)` |
| ImageField | 图片 | `image = models.ImageField('图片', upload_to='images/%Y/%m/')` |
| FileField | 文件 | `file = models.FileField('附件', upload_to='files/%Y/%m/')` |

### 2.2 关系字段

| 字段类型 | 用途 | 示例 |
|---------|------|------|
| ForeignKey | 外键(一对多) | `category = models.ForeignKey('Category', on_delete=models.CASCADE)` |
| ManyToManyField | 多对多 | `roles = models.ManyToManyField('Role', blank=True)` |
| OneToOneField | 一对一 | `profile = models.OneToOneField('Profile', on_delete=models.CASCADE)` |
| ForeignKey('self') | 自关联 | `parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True)` |

### 2.3 字段选项

```python
# 常用选项
name = models.CharField(
    '名称',                    # verbose_name
    max_length=100,            # 最大长度
    unique=True,               # 唯一
    null=True,                 # 数据库允许NULL
    blank=True,                # 表单允许空
    default='',                # 默认值
    choices=[('a', 'A'), ('b', 'B')],  # 选项
    verbose_name='名称',       # 中文名
    help_text='帮助文本',      # 帮助提示
)
```

---

## 三、常用业务字段组合

### 3.1 基础信息

```python
# 基础信息
name = models.CharField('名称', max_length=100)
code = models.CharField('编码', max_length=50, unique=True)
description = models.TextField('描述', blank=True)
sort = models.IntegerField('排序', default=0)
status = models.BooleanField('状态', default=True)
is_used = models.BooleanField('是否启用', default=True)
```

### 3.2 组织架构

```python
# 组织关联
dept = models.ForeignKey('Organization', on_delete=models.SET_NULL, 
                        null=True, blank=True, verbose_name='所属部门')
company = models.ForeignKey('Organization', on_delete=models.SET_NULL,
                           null=True, blank=True, verbose_name='所属公司',
                           related_name='xxx_company')
```

### 3.3 人员关联

```python
# 人员关联
create_by = models.ForeignKey('system.User', on_delete=models.SET_NULL,
                             null=True, blank=True, verbose_name='创建人',
                             related_name='%(class)s_created')
update_by = models.ForeignKey('system.User', on_delete=models.SET_NULL,
                             null=True, blank=True, verbose_name='更新人',
                             related_name='%(class)s_updated')
leader = models.ForeignKey('system.User', on_delete=models.SET_NULL,
                          null=True, blank=True, verbose_name='负责人')
```

### 3.4 分类/层级

```python
# 分类层级
category = models.ForeignKey('Category', on_delete=models.CASCADE,
                           verbose_name='分类', related_name='items')
parent = models.ForeignKey('self', on_delete=models.CASCADE,
                          null=True, blank=True, verbose_name='父级',
                          related_name='children')
level = models.IntegerField('层级', default=1)
path = models.CharField('路径', max_length=500, default='', blank=True)
```

### 3.5 金额/统计

```python
# 金额相关
price = models.DecimalField('价格', max_digits=10, decimal_places=2, default=0)
amount = models.DecimalField('金额', max_digits=15, decimal_places=2, default=0)
cost = models.DecimalField('成本', max_digits=10, decimal_places=2, default=0)

# 数量相关
quantity = models.IntegerField('数量', default=0)
stock = models.IntegerField('库存', default=0)
count = models.IntegerField('次数', default=0)
```

### 3.6 文件/图片

```python
# 文件
image = models.ImageField('图片', upload_to='images/%Y/%m/', null=True, blank=True)
avatar = models.ImageField('头像', upload_to='avatars/', null=True, blank=True)
file = models.FileField('附件', upload_to='files/%Y/%m/', null=True, blank=True)
url = models.CharField('链接', max_length=500, blank=True)
```

### 3.7 时间相关

```python
# 时间
start_date = models.DateField('开始日期', null=True, blank=True)
end_date = models.DateField('结束日期', null=True, blank=True)
expire_time = models.DateTimeField('过期时间', null=True, blank=True)
```

### 3.8 审批/状态

```python
# 审批流程
workflow = models.ForeignKey('wf.Workflow', on_delete=models.CASCADE,
                            null=True, blank=True, verbose_name='工作流')
state = models.CharField('状态', max_length=20, default='draft',
                        choices=[('draft', '草稿'), ('pending', '待审批'), ('approved', '已批准'), ('rejected', '已拒绝')])
```

### 3.9 扩展字段

```python
# JSON 扩展
extra = models.JSONField('扩展信息', default=dict, blank=True)
config = models.JSONField('配置', default=dict, blank=True)
tags = models.JSONField('标签', default=list, blank=True)
```

---

## 四、完整示例

### 4.1 产品模型

```python
class Product(CommonBModel):
    """产品"""
    name = models.CharField('产品名称', max_length=200)
    code = models.CharField('产品编码', max_length=50, unique=True)
    category = models.ForeignKey('Category', on_delete=models.CASCADE,
                               verbose_name='产品分类', related_name='products')
    brand = models.ForeignKey('Brand', on_delete=models.SET_NULL,
                             null=True, blank=True, verbose_name='品牌')
    price = models.DecimalField('销售价', max_digits=10, decimal_places=2)
    cost = models.DecimalField('成本价', max_digits=10, decimal_places=2, default=0)
    stock = models.IntegerField('库存', default=0)
    image = models.ImageField('产品图片', upload_to='products/', null=True, blank=True)
    description = models.TextField('产品描述', blank=True)
    specs = models.JSONField('规格参数', default=dict, blank=True)
    status = models.BooleanField('上架状态', default=True)
    sort = models.IntegerField('排序', default=0)
    
    class Meta:
        verbose_name = '产品'
        verbose_name_plural = '产品'
        ordering = ['-create_time']
    
    def __str__(self):
        return self.name
```

### 4.2 订单模型

```python
class Order(CommonBModel):
    """订单"""
    order_no = models.CharField('订单号', max_length=50, unique=True)
    customer = models.ForeignKey('Customer', on_delete=models.CASCADE,
                               verbose_name='客户', related_name='orders')
    total_amount = models.DecimalField('订单金额', max_digits=12, decimal_places=2)
    paid_amount = models.DecimalField('实付金额', max_digits=12, decimal_places=2, default=0)
    status = models.CharField('订单状态', max_length=20, 
                             choices=[('pending', '待支付'), ('paid', '已支付'), 
                                     ('shipped', '已发货'), ('completed', '已完成'), 
                                     ('cancelled', '已取消')],
                             default='pending')
    pay_time = models.DateTimeField('支付时间', null=True, blank=True)
    ship_time = models.DateTimeField('发货时间', null=True, blank=True)
    remark = models.CharField('备注', max_length=500, blank=True)
    
    class Meta:
        verbose_name = '订单'
        ordering = ['-create_time']
    
    def __str__(self):
        return self.order_no
```

---

## 五、前端字段映射

| Django 字段 | 前端组件 | 说明 |
|------------|---------|------|
| CharField(choices) | el-select | 下拉选择 |
| BooleanField | el-switch | 开关 |
| IntegerField/DecimalField | el-input-number | 数字输入 |
| TextField | el-input(type=textarea) | 文本域 |
| DateField | el-date-picker | 日期选择 |
| DateTimeField | el-date-picker(type=datetime) | 日期时间 |
| ImageField | el-upload | 图片上传 |
| FileField | el-upload | 文件上传 |
| ForeignKey | el-select + remote | 下拉选择 |
| ManyToManyField | el-select(multiple) | 多选 |
| JSONField | 自定义组件 | JSON 编辑器 |


path: templates/backend/model.py
content: # -*- coding: utf-8 -*-
"""
{{ module_name }} 模块 Model 模板
自动生成时间: {{ generate_time }}
"""

from django.db import models
from utils.model import CommonBModel


{% for model in models %}
class {{ model.name }}(CommonBModel):
    """{{ model.verbose_name|default:model.name }}"""
    {% for field in model.fields %}
    {{ field.name }} = models.{{ field.type }}(
        {% if field.verbose_name %}
        '{{ field.verbose_name }}',
        {% endif %}
        {% if field.max_length %}
        max_length={{ field.max_length }},
        {% endif %}
        {% if field.max_digits %}
        max_digits={{ field.max_digits }},
        {% endif %}
        {% if field.decimal_places %}
        decimal_places={{ field.decimal_places }},
        {% endif %}
        {% if field.default is not none %}
        default={{ field.default }},
        {% endif %}
        {% if field.null %}
        null=True,
        {% endif %}
        {% if field.blank %}
        blank=True,
        {% endif %}
        {% if field.unique %}
        unique=True,
        {% endif %}
        {% if field.related_name %}
        related_name='{{ field.related_name }}',
        {% endif %}
        {% if field.on_delete %}
        on_delete=models.{{ field.on_delete }},
        {% endif %}
    )
    {% endfor %}

    class Meta:
        verbose_name = '{{ model.verbose_name|default:model.name }}'
        verbose_name_plural = verbose_name
        ordering = ['-create_time']

    def __str__(self):
        return self.name

{% endfor %}


path: templates/backend/serializer.py
content: # -*- coding: utf-8 -*-
"""
{{ module_name }} 模块 Serializer 模板
自动生成时间: {{ generate_time }}
"""

from rest_framework import serializers
from .models import (
    {% for model in models %}
    {{ model.name }},
    {% endfor %}
)


{% for model in models %}
class {{ model.name }}Serializer(serializers.ModelSerializer):
    """{{ model.verbose_name|default:model.name }}序列化"""
    {% if model.related_fields %}
    {% for rf in model.related_fields %}
    {{ rf.name }}_name = serializers.CharField(source='{{ rf.name }}.{{ rf.display_field }}', read_only=True)
    {% endfor %}
    {% endif %}

    class Meta:
        model = {{ model.name }}
        fields = '__all__'

    @staticmethod
    def setup_eager_loading(queryset):
        """性能优化: 预加载关联数据"""
        {% if model.related_fields %}
        queryset = queryset.select_related({% for rf in model.related_fields %}'{{ rf.name }}'{% if not forloop.last %}, {% endif %}{% endfor %})
        {% endif %}
        return queryset


class {{ model.name }}CreateSerializer(serializers.ModelSerializer):
    """{{ model.name }}创建/更新序列化"""
    class Meta:
        model = {{ model.name }}
        fields = [{% for field in model.fields %}'{{ field.name }}'{% if not forloop.last %}, {% endif %}{% endfor %}]

{% endfor %}


path: templates/backend/urls.py
content: # -*- coding: utf-8 -*-
"""
{{ module_name }} 模块 URL 路由模板
自动生成时间: {{ generate_time }}
"""

from rest_framework.routers import DefaultRouter
from .views import (
    {% for model in models %}
    {{ model.name }}ViewSet,
    {% endfor %}
)

router = DefaultRouter()

{% for model in models %}
router.register(r'{{ model.name|lower }}', {{ model.name }}ViewSet, basename='{{ model.name|lower }}')
{% endfor %}

urlpatterns = router.urls


path: templates/backend/viewset.py
content: # -*- coding: utf-8 -*-
"""
{{ module_name }} 模块 ViewSet 模板
自动生成时间: {{ generate_time }}
"""

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import action
from rest_framework.response import Response

from .models import (
    {% for model in models %}
    {{ model.name }},
    {% endfor %}
)
from .serializers import (
    {% for model in models %}
    {{ model.name }}Serializer, {{ model.name }}CreateSerializer,
    {% endfor %}
)
from utils.permission import RbacPermission


{% for model in models %}
class {{ model.name }}ViewSet(ModelViewSet):
    """{{ model.verbose_name|default:model.name }}管理"""
    perms_map = {
        'get': '*',
        'post': '{{ module_name }}_{{ model.name|lower }}_create',
        'put': '{{ module_name }}_{{ model.name|lower }}_update',
        'delete': '{{ module_name }}_{{ model.name|lower }}_delete',
    }
    permission_classes = [IsAuthenticated, RbacPermission]
    queryset = {{ model.name }}.objects.all()
    
    # 搜索、过滤、排序
    filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
    search_fields = [{% for field in model.search_fields %}'{{ field }}'{% if not forloop.last %}, {% endif %}{% endfor %}]
    filterset_fields = [{% for field in model.filter_fields %}'{{ field }}'{% if not forloop.last %}, {% endif %}{% endfor %}]
    ordering_fields = [{% for field in model.ordering_fields %}'{{ field }}'{% if not forloop.last %}, {% endif %}{% endfor %}]
    ordering = ['-create_time']
    
    def get_serializer_class(self):
        if self.action in ['list', 'retrieve']:
            return {{ model.name }}Serializer
        return {{ model.name }}CreateSerializer
    
    def get_queryset(self):
        """数据权限过滤"""
        queryset = super().get_queryset()
        user = self.request.user
        
        # 超级管理员看全部
        if user.is_superuser:
            return queryset
        
        # 根据角色数据权限过滤
        {% if model.data_scope == 'department' %}
        from utils.queryset import get_data_scope
        return get_data_scope(user, queryset)
        {% else %}
        return queryset
        {% endif %}

{% endfor %}


path: templates/frontend/api.js
content: // {{ module_name }} 模块 API 接口
// 自动生成时间: {{ generate_time }}

import request from '@/utils/request'

{% for model in models %}
// {{ model.name }} API
export function get{{ model.name }}List(params) {
  return request({
    url: '/{{ module_name }}/{{ model.name|lower }}/',
    method: 'get',
    params
  })
}

export function get{{ model.name }}(id) {
  return request({
    url: `/{{ module_name }}/{{ model.name|lower }}/${id}/`,
    method: 'get'
  })
}

export function create{{ model.name }}(data) {
  return request({
    url: '/{{ module_name }}/{{ model.name|lower }}/',
    method: 'post',
    data
  })
}

export function update{{ model.name }}(id, data) {
  return request({
    url: `/{{ module_name }}/{{ model.name|lower }}/${id}/`,
    method: 'put',
    data
  })
}

export function delete{{ model.name }}(id) {
  return request({
    url: `/{{ module_name }}/{{ model.name|lower }}/${id}/`,
    method: 'delete'
  })
}

{% endfor %}


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (HIGH)