4.4 KiB
4.4 KiB
删除规范
概述
统一使用软删除机制,通过 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 示例
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 示例
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 响应封装和文案统一。
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 扩展
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 层实现
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。