签入版本
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
# 第四章 架构设计 - 数据库设计
|
||||
|
||||
## 4.1 数据库设计概述
|
||||
|
||||
项目使用 MySQL 8.0 作为主数据库,通过 Django ORM 进行数据访问。所有业务表继承 BaseModel 抽象基类,自动获得 6 个通用字段。
|
||||
|
||||
## 4.2 通用字段规范
|
||||
|
||||
### BaseModel 字段定义
|
||||
|
||||
所有业务表继承 `BaseModel`(`application/models.py`),自动包含以下字段:
|
||||
|
||||
```python
|
||||
class BaseModel(models.Model):
|
||||
"""基础模型抽象类"""
|
||||
|
||||
id = models.AutoField(
|
||||
auto_created=True, primary_key=True, serialize=False,
|
||||
verbose_name='主键ID', db_comment='主键ID'
|
||||
)
|
||||
|
||||
create_user = models.CharField(
|
||||
null=True, max_length=50, default=None, db_default=None,
|
||||
verbose_name='创建人', db_comment='创建人'
|
||||
)
|
||||
|
||||
create_time = models.DateTimeField(
|
||||
null=True, auto_now_add=True,
|
||||
verbose_name="创建时间", db_comment='创建时间'
|
||||
)
|
||||
|
||||
update_user = models.CharField(
|
||||
null=True, max_length=50, default=None, db_default=None,
|
||||
verbose_name='更新人', db_comment='更新人'
|
||||
)
|
||||
|
||||
update_time = models.DateTimeField(
|
||||
null=True, auto_now=True,
|
||||
verbose_name="更新时间", db_comment='更新时间'
|
||||
)
|
||||
|
||||
is_delete = models.BooleanField(
|
||||
default=0, db_default=0,
|
||||
verbose_name="逻辑删除",
|
||||
db_comment='逻辑删除:0-正常 1-已删除'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
```
|
||||
|
||||
### 字段说明
|
||||
|
||||
| 字段 | 类型 | 约束 | 默认值 | 说明 |
|
||||
|------|------|------|--------|------|
|
||||
| `id` | AutoField | PK, 自增 | - | 主键ID |
|
||||
| `create_user` | CharField(50) | NULL | None | 创建人用户名 |
|
||||
| `create_time` | DateTimeField | NULL | auto_now_add | 创建时间,自动填充 |
|
||||
| `update_user` | CharField(50) | NULL | None | 更新人用户名 |
|
||||
| `update_time` | DateTimeField | NULL | auto_now | 更新时间,自动刷新 |
|
||||
| `is_delete` | BooleanField | NOT NULL | 0 | 逻辑删除标识 |
|
||||
|
||||
### 字段自动管理
|
||||
|
||||
- `create_time`:使用 `auto_now_add=True`,仅在创建时自动设置当前时间
|
||||
- `update_time`:使用 `auto_now=True`,每次保存时自动更新为当前时间
|
||||
- `create_user` 和 `update_user`:需要业务代码手动赋值
|
||||
|
||||
## 4.3 表名命名规范
|
||||
|
||||
### 表前缀配置
|
||||
|
||||
所有业务表使用统一的前缀,通过 `config/env.py` 配置:
|
||||
|
||||
```python
|
||||
DATABASE_PREFIX = os.getenv('DATABASE_PREFIX', "django_")
|
||||
```
|
||||
|
||||
### 表名生成函数
|
||||
|
||||
使用 `get_table_name()` 函数自动生成带前缀的表名:
|
||||
|
||||
```python
|
||||
# utils/common.py
|
||||
def get_table_name(name):
|
||||
"""获取带前缀的表名"""
|
||||
from config.env import DATABASE_PREFIX
|
||||
return f"{DATABASE_PREFIX}{name}"
|
||||
```
|
||||
|
||||
### 表名示例
|
||||
|
||||
| 模块 | 配置的表名 | 实际表名 |
|
||||
|------|-----------|----------|
|
||||
| 案例 | `get_table_name('example')` | `django_example` |
|
||||
| 用户 | `get_table_name('user')` | `django_user` |
|
||||
| 角色 | `get_table_name('role')` | `django_role` |
|
||||
| 菜单 | `get_table_name('menu')` | `django_menu` |
|
||||
| 部门 | `get_table_name('dept')` | `django_dept` |
|
||||
| 字典 | `get_table_name('dict')` | `django_dict` |
|
||||
|
||||
## 4.4 软删除设计
|
||||
|
||||
### 设计原理
|
||||
|
||||
系统采用软删除策略,所有业务表包含 `is_delete` 字段:
|
||||
|
||||
- `is_delete = 0`:正常记录(默认值)
|
||||
- `is_delete = 1`:已删除记录
|
||||
|
||||
### 软删除实现
|
||||
|
||||
```python
|
||||
# Service层删除操作
|
||||
def delete_examples(instance_ids):
|
||||
"""删除案例(批量删除)"""
|
||||
id_list = [int(id_str.strip())
|
||||
for id_str in instance_ids.split(',') if id_str.strip()]
|
||||
|
||||
# 批量更新删除标识(逻辑删除)
|
||||
updated_count = Example.objects.filter(
|
||||
id__in=id_list, is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
return R.ok(msg=f"本次共删除{updated_count}条数据")
|
||||
```
|
||||
|
||||
### 查询过滤
|
||||
|
||||
所有查询都需要过滤已删除的记录:
|
||||
|
||||
```python
|
||||
# 分页查询
|
||||
query = Example.objects.filter(is_delete=False)
|
||||
|
||||
# 详情查询
|
||||
instance = Example.objects.filter(id=id, is_delete=False).first()
|
||||
|
||||
# 列表查询
|
||||
queryset = Example.objects.filter(is_delete=False, status=1)
|
||||
```
|
||||
|
||||
### 软删除优势
|
||||
|
||||
| 优势 | 说明 |
|
||||
|------|------|
|
||||
| 数据可恢复 | 误删除的数据可以恢复 |
|
||||
| 审计追踪 | 保留删除记录的历史 |
|
||||
| 关联完整 | 不破坏外键关联关系 |
|
||||
| 操作安全 | 避免物理删除造成的数据丢失 |
|
||||
|
||||
## 4.5 字段顺序重排
|
||||
|
||||
### 设计目标
|
||||
|
||||
通过 Django 的 `class_prepared` 信号,自动将 BaseModel 的公共字段移到业务字段之后,使数据库表结构更清晰。
|
||||
|
||||
### 实现代码
|
||||
|
||||
```python
|
||||
# application/models.py
|
||||
BASE_FIELD_NAMES = ['id', 'create_user', 'create_time',
|
||||
'update_user', 'update_time', 'is_delete']
|
||||
|
||||
def _reorder_fields(sender, **kwargs):
|
||||
"""信号处理函数:重排模型字段顺序"""
|
||||
if not hasattr(sender, '_meta') or sender._meta.abstract:
|
||||
return
|
||||
|
||||
# 检查是否有公共字段
|
||||
has_base_fields = any(
|
||||
f.name in BASE_FIELD_NAMES for f in sender._meta.local_fields
|
||||
)
|
||||
if not has_base_fields:
|
||||
return
|
||||
|
||||
# 分离公共字段和业务字段
|
||||
base_fields = []
|
||||
business_fields = []
|
||||
|
||||
for field in sender._meta.local_fields:
|
||||
if field.name in BASE_FIELD_NAMES:
|
||||
base_fields.append(field)
|
||||
else:
|
||||
business_fields.append(field)
|
||||
|
||||
# 重新排列:业务字段在前,公共字段在后
|
||||
sender._meta.local_fields = business_fields + base_fields
|
||||
|
||||
# 注册信号处理器
|
||||
class_prepared.connect(_reorder_fields)
|
||||
```
|
||||
|
||||
### 重排效果
|
||||
|
||||
```
|
||||
重排前:id, create_user, create_time, name, status, sort, update_user, update_time, is_delete
|
||||
重排后:name, status, sort, id, create_user, create_time, update_user, update_time, is_delete
|
||||
```
|
||||
|
||||
## 4.6 数据库表结构示例
|
||||
|
||||
### 案例表 (django_example)
|
||||
|
||||
```sql
|
||||
CREATE TABLE `django_example` (
|
||||
`name` varchar(100) NOT NULL COMMENT '案例名称',
|
||||
`avatar` varchar(255) DEFAULT NULL COMMENT '案例图片',
|
||||
`type` int NOT NULL COMMENT '案例类型:1-类型1 2-类型2 3-类型3 4-类型4',
|
||||
`status` int NOT NULL COMMENT '案例状态:1-正常 2-禁用',
|
||||
`sort` int NOT NULL COMMENT '排序',
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`create_user` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime(6) DEFAULT NULL COMMENT '创建时间',
|
||||
`update_user` varchar(50) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime(6) DEFAULT NULL COMMENT '更新时间',
|
||||
`is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_example_name` (`name`)
|
||||
) ENGINE=InnoDB COMMENT='案例表';
|
||||
```
|
||||
|
||||
### 用户表 (django_user)
|
||||
|
||||
```sql
|
||||
CREATE TABLE `django_user` (
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`password` varchar(128) NOT NULL COMMENT '密码',
|
||||
`realname` varchar(50) DEFAULT NULL COMMENT '真实姓名',
|
||||
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
|
||||
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
|
||||
`avatar` varchar(255) DEFAULT NULL COMMENT '头像',
|
||||
`status` int NOT NULL DEFAULT 1 COMMENT '状态:1-正常 2-禁用',
|
||||
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`create_user` varchar(50) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime(6) DEFAULT NULL COMMENT '创建时间',
|
||||
`update_user` varchar(50) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` datetime(6) DEFAULT NULL COMMENT '更新时间',
|
||||
`is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除:0-正常 1-已删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_user_username` (`username`)
|
||||
) ENGINE=InnoDB COMMENT='用户表';
|
||||
```
|
||||
|
||||
## 4.7 字段类型映射
|
||||
|
||||
| Django 字段 | MySQL 类型 | 说明 |
|
||||
|-------------|-----------|------|
|
||||
| `AutoField` | `INT AUTO_INCREMENT` | 自增主键 |
|
||||
| `CharField` | `VARCHAR(n)` | 变长字符串 |
|
||||
| `TextField` | `LONGTEXT` | 长文本 |
|
||||
| `IntegerField` | `INT` | 整数 |
|
||||
| `BooleanField` | `TINYINT(1)` | 布尔值 |
|
||||
| `DateTimeField` | `DATETIME(6)` | 日期时间 |
|
||||
| `DecimalField` | `DECIMAL(p,s)` | 精确小数 |
|
||||
| `ImageField` | `VARCHAR(255)` | 图片路径 |
|
||||
| `ForeignKey` | `INT` + 外键约束 | 外键关联 |
|
||||
|
||||
## 4.8 索引设计规范
|
||||
|
||||
### 自动索引
|
||||
|
||||
- 主键 `id` 自动创建主键索引
|
||||
- 唯一约束字段自动创建唯一索引
|
||||
|
||||
### 手动索引
|
||||
|
||||
在模型定义中使用 `db_index=True` 为常用查询字段创建索引:
|
||||
|
||||
```python
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
db_index=True, # 创建索引
|
||||
verbose_name="案例名称"
|
||||
)
|
||||
```
|
||||
|
||||
### 索引命名规范
|
||||
|
||||
```
|
||||
idx_<表名>_<字段名>
|
||||
```
|
||||
|
||||
示例:`idx_example_name`、`idx_user_username`
|
||||
|
||||
## 4.9 数据库迁移
|
||||
|
||||
### 生成迁移文件
|
||||
|
||||
```bash
|
||||
python manage.py makemigrations <app_name>
|
||||
```
|
||||
|
||||
### 执行迁移
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
### 代码生成器自动迁移
|
||||
|
||||
代码生成器在生成新模块时会自动执行迁移:
|
||||
|
||||
```python
|
||||
# generator_config.py
|
||||
os.system('python manage.py makemigrations')
|
||||
os.system('python manage.py migrate')
|
||||
```
|
||||
Reference in New Issue
Block a user