Files
djangoadmin-wiki/DjangoAdmin_Django_AntdVue/zh/volume3/database-design.md
T
2026-09-12 23:12:15 +08:00

309 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第四章 架构设计 - 数据库设计
## 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')
```