Files
djangoadmin-wiki/DjangoAdmin_Tornado_EleVue/zh/volume7/deletion.md
T
2026-09-16 10:11:44 +08:00

166 lines
4.4 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.
# 删除规范
## 概述
统一使用软删除机制,通过 `is_delete` 字段标记记录状态,不物理删除数据。删除操作分为单条删除和批量删除两种方式。
:::tip 软删除约定
- `is_delete = 0`:正常记录(默认值)
- `is_delete = 1`:已删除记录
- 所有查询方法自动过滤 `is_delete = 0`,业务层无需关心
:::
## 单条删除
### URL 格式
```
DELETE /api/v1/{module}/delete/{id}
```
支持逗号分隔的多 ID 删除:
```
DELETE /api/v1/position/delete/1,2,3
```
### Handler 示例
```python
class PositionDeleteHandler(BaseHandler):
@permission_required("sys:position:delete")
@check_demo
@operation_log("岗位管理", "删除")
async def delete(self, id):
"""根据ID删除单个岗位"""
return await position_service.delete(self, id)
```
:::tip 装饰器顺序
删除接口的装饰器顺序:`@permission_required` → `@check_demo` → `@operation_log`
:::
## 批量删除
### 请求格式
```
POST /api/v1/{module}/batchDelete
Content-Type: application/json
[1, 2, 3]
```
### Handler 示例
```python
class PositionBatchDeleteHandler(BaseHandler):
@permission_required("sys:position:delete")
@check_demo
@operation_log("岗位管理", "批量删除")
async def post(self):
"""批量删除岗位"""
return await position_service.batch_delete(self)
```
## 删除流程
### 原理
Repository 层的 `batch_delete` 只做数据原语(软删除 + 返回条数),Service 层负责 R 响应封装和文案统一。
```python
async def delete(self, handler, ids) -> R:
try:
id_list = list(dict.fromkeys(parse_id_list(str(ids))))
if not id_list:
return R.failed(handler, "记录ID不存在")
if len(self.repo.get_by_ids(id_list)) != len(id_list):
return R.failed(handler, "记录不存在")
err = self._before_delete(ids)
if err:
return R.failed(handler, err)
count = self.repo.batch_delete(ids)
return R.ok(handler, msg="本次共删除{0}条数据".format(count))
finally:
self.repo.close()
```
### 自定义 Service 扩展
```python
class PositionService(BaseService):
def _before_delete(self, ids) -> Optional[str]:
"""删除前校验:存在用户引用时禁止删除"""
id_list = parse_id_list(str(ids))
if id_list and user_repo.filter(
User.position_id.in_(id_list), User.is_delete == 0
).first():
return "存在用户引用该岗位,请先调整用户岗位"
return None
```
:::tip _before_delete 钩子
- 返回 `None`:放行,继续删除
- 返回字符串:拦截,返回 `R.failed(字符串)`
- 用于检查子级引用、业务约束等
:::
## 删除流程
```
1. Endpoint 接收请求
↓
2. Service.delete(ids) 或 Service.batch_delete(request)
↓
3. _before_delete(ids) 钩子校验
↓(拦截则返回 R.failed)
4. delete(handler, ids)
↓
5. repo.batch_delete(ids) 软删除
↓
6. 返回 R.ok(msg="本次共删除N条数据")
```
## Repository 层实现
```python
def batch_delete(self, ids_str) -> int:
"""按ID软删除,返回实际删除条数"""
id_list = parse_id_list(str(ids_str))
if not id_list:
return 0
records = self.db.query(self.model).filter(
self.model.id.in_(id_list), self._soft_col() == 0
).all()
for record in records:
setattr(record, self.soft_delete_col, 1)
return len(records)
```
:::tip 返回值说明
`batch_delete` 返回实际软删除的条数。如果传入的 ID 中包含已删除或不存在的记录,返回值会小于入参数量,此时 `delete` 会返回失败提示。
:::
## 权限标识
| 操作 | 权限标识 | 说明 |
|------|---------|------|
| 单条删除 | `sys:{module}:delete` | 删除单条记录 |
| 批量删除 | `sys:{module}:batchDelete` | 批量删除记录 |
## 常见错误提示
| 提示 | 原因 |
|------|------|
| "记录ID不存在" | 入参为空或格式错误 |
| "记录不存在" | 部分或全部 ID 对应的记录已删除/不存在 |
| "存在用户引用该岗位" | _before_delete 钩子拦截 |
## 总结
删除规范统一使用软删除(`is_delete` 标记),支持单条删除(逗号分隔 ID)和批量删除(JSON 数组)。Repository 层做数据原语,Service 层通过 `delete` 统一封装响应。自定义 Service 通过 `_before_delete` 钩子添加业务校验。批量删除端点必须为 `async def`。