签入版本
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
# 删除规范
|
||||
|
||||
## 概述
|
||||
|
||||
统一使用软删除机制,通过 `is_delete` 字段标记记录状态,不物理删除数据。删除操作支持逗号分隔的多 ID 批量删除。
|
||||
|
||||
:::tip 软删除约定
|
||||
- `is_delete = False`(0):正常记录(默认值)
|
||||
- `is_delete = True`(1):已删除记录
|
||||
- 所有查询方法自动过滤 `is_delete=False`,业务层无需关心
|
||||
:::
|
||||
|
||||
## 软删除 vs 硬删除
|
||||
|
||||
| 维度 | 软删除 | 硬删除 |
|
||||
|------|--------|--------|
|
||||
| 实现方式 | 更新 `is_delete=True` | `DELETE FROM table` |
|
||||
| 数据可恢复 | ✅ 可恢复 | ❌ 不可恢复 |
|
||||
| 查询影响 | 需加 `is_delete=False` | 数据已不存在 |
|
||||
| 存储空间 | 占用(数据仍在表中) | 释放 |
|
||||
| 适用场景 | 业务数据(用户、订单等) | 日志、临时数据 |
|
||||
| 项目约定 | ✅ 统一使用 | ❌ 禁止使用 |
|
||||
|
||||
## BaseModel 公共字段
|
||||
|
||||
所有业务模型继承 `BaseModel`,自动包含 `is_delete` 字段:
|
||||
|
||||
```python
|
||||
# application/models.py
|
||||
class BaseModel(models.Model):
|
||||
"""基础模型类"""
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
id = models.AutoField(primary_key=True)
|
||||
create_user = models.CharField(max_length=50, null=True, blank=True)
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
update_user = models.CharField(max_length=50, null=True, blank=True)
|
||||
update_time = models.DateTimeField(auto_now=True)
|
||||
is_delete = models.IntegerField(default=0, db_comment='是否删除:0-正常 1-已删除')
|
||||
```
|
||||
|
||||
## 删除接口
|
||||
|
||||
### URL 格式
|
||||
|
||||
```
|
||||
DELETE /{module}/delete/{id}
|
||||
```
|
||||
|
||||
支持逗号分隔的多 ID 删除:
|
||||
|
||||
```
|
||||
DELETE /example/delete/1,2,3
|
||||
```
|
||||
|
||||
### View 示例
|
||||
|
||||
```python
|
||||
@method_decorator(check_login, name="delete")
|
||||
class ExampleDeleteView(PermissionRequired, View):
|
||||
"""删除案例视图"""
|
||||
permission_required = ('sys:example:delete',)
|
||||
|
||||
@operation_log(title="案例管理-删除记录", log_type=LogType.DELETE)
|
||||
def delete(self, request, id):
|
||||
# 演示环境禁止操作
|
||||
if DJANGO_DEMO:
|
||||
return R.failed("演示环境,暂无操作权限")
|
||||
|
||||
result = services.delete_examples(id)
|
||||
return result
|
||||
```
|
||||
|
||||
## Service 实现
|
||||
|
||||
```python
|
||||
def delete_examples(instance_ids):
|
||||
"""删除案例(批量删除)"""
|
||||
if not instance_ids:
|
||||
return R.failed("记录ID不存在")
|
||||
|
||||
try:
|
||||
# 解析ID列表
|
||||
id_list = [int(id_str.strip()) for id_str in instance_ids.split(',') if id_str.strip()]
|
||||
if not id_list:
|
||||
return R.failed("无效的记录ID")
|
||||
|
||||
# 批量更新删除标识(逻辑删除)
|
||||
updated_count = Example.objects.filter(
|
||||
id__in=id_list,
|
||||
is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
return R.ok(msg=f"本次共删除{updated_count}条数据")
|
||||
except ValueError:
|
||||
return R.failed("记录ID格式错误")
|
||||
except Exception as e:
|
||||
logging.error(f"删除案例异常,IDs: {instance_ids}, 错误: {str(e)}")
|
||||
return R.failed(msg="删除失败,请稍后重试")
|
||||
```
|
||||
|
||||
:::tip 返回值说明
|
||||
`delete` 方法返回实际软删除的条数。如果传入的 ID 中包含已删除或不存在的记录,返回值会小于入参数量。
|
||||
:::
|
||||
|
||||
## 删除流程
|
||||
|
||||
```
|
||||
1. View 接收请求(id 参数,逗号分隔)
|
||||
↓
|
||||
2. 演示模式检查(DJANGO_DEMO)
|
||||
↓(拦截则返回 R.failed)
|
||||
3. Service.delete_examples(id)
|
||||
↓
|
||||
4. 解析 ID 列表(逗号分隔转 list)
|
||||
↓
|
||||
5. ORM 批量更新 is_delete=True
|
||||
↓
|
||||
6. 返回 R.ok(msg="本次共删除N条数据")
|
||||
```
|
||||
|
||||
## 查询过滤
|
||||
|
||||
所有查询方法必须过滤 `is_delete=False`:
|
||||
|
||||
```python
|
||||
# 分页查询
|
||||
query = Example.objects.filter(is_delete=False)
|
||||
|
||||
# 详情查询
|
||||
instance = Example.objects.filter(is_delete=False, id=id).first()
|
||||
|
||||
# 列表查询
|
||||
queryset = Example.objects.filter(is_delete=False, status=1)
|
||||
|
||||
# 带筛选条件的查询
|
||||
query = Example.objects.filter(is_delete=False, name__contains=name)
|
||||
```
|
||||
|
||||
:::warning 常见错误
|
||||
忘记加 `is_delete=False` 是最常见的 bug,会导致已删除的数据重新出现在列表中。建议在代码审查时重点检查。
|
||||
:::
|
||||
|
||||
## 级联删除处理
|
||||
|
||||
当模块之间存在关联关系时,删除父记录需要同步处理子记录:
|
||||
|
||||
```python
|
||||
def delete_role(role_ids):
|
||||
"""删除角色(同步清理关联数据)"""
|
||||
id_list = [int(id_str.strip()) for id_str in role_ids.split(',')]
|
||||
|
||||
# 1. 软删除角色
|
||||
updated_count = Role.objects.filter(
|
||||
id__in=id_list, is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
# 2. 同步软删除角色菜单关联
|
||||
RoleMenu.objects.filter(
|
||||
role_id__in=id_list, is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
# 3. 同步软删除用户角色关联
|
||||
UserRole.objects.filter(
|
||||
role_id__in=id_list, is_delete=False
|
||||
).update(is_delete=True)
|
||||
|
||||
return R.ok(msg=f"本次共删除{updated_count}条数据")
|
||||
```
|
||||
|
||||
## 数据恢复
|
||||
|
||||
软删除的数据可以通过恢复接口重新启用:
|
||||
|
||||
```python
|
||||
def restore_examples(instance_ids):
|
||||
"""恢复已删除的案例"""
|
||||
id_list = [int(id_str.strip()) for id_str in instance_ids.split(',')]
|
||||
|
||||
updated_count = Example.objects.filter(
|
||||
id__in=id_list, is_delete=True
|
||||
).update(is_delete=False)
|
||||
|
||||
return R.ok(msg=f"本次共恢复{updated_count}条数据")
|
||||
```
|
||||
|
||||
:::tip 恢复场景
|
||||
数据恢复通常用于:
|
||||
1. 误删除后的数据恢复
|
||||
2. 回收站功能
|
||||
3. 数据审计
|
||||
:::
|
||||
|
||||
## 权限标识
|
||||
|
||||
| 操作 | 权限标识 | 说明 |
|
||||
|------|---------|------|
|
||||
| 删除 | `sys:{module}:delete` | 删除记录(支持批量) |
|
||||
|
||||
## 常见错误提示
|
||||
|
||||
| 提示 | 原因 |
|
||||
|------|------|
|
||||
| "记录ID不存在" | 入参为空 |
|
||||
| "无效的记录ID" | ID 格式错误或全部无效 |
|
||||
| "记录ID格式错误" | ID 包含非数字字符 |
|
||||
|
||||
## 最佳实践
|
||||
|
||||
```
|
||||
1. 统一软删除:所有业务数据使用 is_delete 字段,禁止物理删除
|
||||
2. 查询过滤:所有查询加 is_delete=False,避免遗漏
|
||||
3. 级联处理:删除父记录时同步处理关联的子记录
|
||||
4. 批量删除:支持逗号分隔的多 ID,提高操作效率
|
||||
5. 错误提示:返回明确的错误信息,便于排查
|
||||
6. 操作日志:删除操作记录操作日志,便于审计
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
删除规范统一使用软删除(`is_delete` 标记),支持逗号分隔的多 ID 批量删除。Service 层解析 ID 列表后通过 ORM 批量更新 `is_delete=True`。所有查询方法自动过滤 `is_delete=False`,业务层无需关心软删除逻辑。级联删除时需同步处理关联数据,保证数据一致性。
|
||||
Reference in New Issue
Block a user