签入版本
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# Service 层
|
||||
|
||||
Service 层是业务逻辑层,负责实现具体的业务规则。简单 CRUD 模块继承 `BaseService` 基类,只需声明差异点即可获得完整的增删改查能力。
|
||||
|
||||
## 文件位置
|
||||
|
||||
```
|
||||
src/modules/position/service.py
|
||||
```
|
||||
|
||||
## 完整代码
|
||||
|
||||
```python
|
||||
# +======================================================================
|
||||
# | 模块: 岗位业务服务层
|
||||
# | 说明: 继承 BaseService 获得通用 CRUD,声明差异点 + 覆盖删除前钩子
|
||||
# +======================================================================
|
||||
"""岗位业务服务。"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from common.utils.helpers import parse_id_list
|
||||
from core.base_service import BaseService
|
||||
from modules.position.models import Position
|
||||
from modules.position.repository import PositionRepository
|
||||
from modules.user.models import User
|
||||
from modules.user.repository import UserRepository
|
||||
|
||||
|
||||
class PositionService(BaseService(Position]):
|
||||
"""岗位业务服务类,继承基础服务获得通用 CRUD 能力。"""
|
||||
|
||||
# ============================================================
|
||||
# 数据访问与模型
|
||||
# ============================================================
|
||||
repo_cls = PositionRepository
|
||||
model = Position
|
||||
|
||||
# ============================================================
|
||||
# 分页差异点
|
||||
# ============================================================
|
||||
page_like_fields = ('name',)
|
||||
page_eq_fields = ('status',)
|
||||
page_order_by = (('sort', 'asc'),)
|
||||
|
||||
# ============================================================
|
||||
# 唯一性校验
|
||||
# ============================================================
|
||||
unique_fields = {'name': '岗位名称不能重复'}
|
||||
|
||||
# ============================================================
|
||||
# 删除前校验
|
||||
# ============================================================
|
||||
def _before_delete(self, ids) -> Optional[str]:
|
||||
"""删除前校验:存在用户引用该岗位时禁止删除。"""
|
||||
id_list = parse_id_list(str(ids))
|
||||
if id_list:
|
||||
user_repo = UserRepository()
|
||||
if user_repo.filter(User.position_id.in_(id_list), User.is_delete == 0).first():
|
||||
return "存在用户引用该岗位,请先调整用户岗位"
|
||||
return None
|
||||
|
||||
|
||||
# 模块级单例
|
||||
position_service = PositionService()
|
||||
```
|
||||
|
||||
## 代码解析
|
||||
|
||||
### 必须声明的差异点
|
||||
|
||||
```python
|
||||
repo_cls = PositionRepository # 关联的 Repository 类(不是实例)
|
||||
model = Position # 关联的模型类
|
||||
```
|
||||
|
||||
:::tip 注意
|
||||
`repo_cls` 是 **类属性**,值为 Repository **类**(不是实例)。`BaseService.__init__` 会自动实例化它。
|
||||
:::
|
||||
|
||||
### 分页查询配置
|
||||
|
||||
```python
|
||||
page_like_fields = ('name',) # 模糊查询字段(LIKE)
|
||||
page_eq_fields = ('status',) # 精确查询字段(=)
|
||||
page_order_by = (('sort', 'asc'),) # 排序规则
|
||||
```
|
||||
|
||||
当调用 `get_page(handler)` 时,基类自动:
|
||||
1. 从 `handler` 的查询参数读取 `pageNo`、`pageSize`
|
||||
2. 对 `page_like_fields` 中的字段执行 `LIKE %keyword%` 查询
|
||||
3. 对 `page_eq_fields` 中的字段执行精确匹配
|
||||
4. 按 `page_order_by` 排序
|
||||
5. 返回分页数据
|
||||
|
||||
### 唯一性校验
|
||||
|
||||
```python
|
||||
unique_fields = {'name': '岗位名称不能重复'}
|
||||
```
|
||||
|
||||
字典的 key 是模型字段名,value 是校验失败时的错误提示。在 `add()` 和 `update()` 时,基类自动查询数据库判断是否重复。
|
||||
|
||||
### 生命周期钩子
|
||||
|
||||
```python
|
||||
def _before_delete(self, ids) -> Optional[str]:
|
||||
```
|
||||
|
||||
`BaseService` 提供以下钩子方法,子类可按需覆盖:
|
||||
|
||||
| 钩子 | 触发时机 | 返回值 |
|
||||
|:----|:----|:----|
|
||||
| `_before_delete(ids)` | 删除操作前 | 返回错误字符串则中止删除,返回 None 则继续 |
|
||||
| `_before_add(handler, data)` | 新增操作前 | 可修改 data(原地修改) |
|
||||
| `_before_update(handler, data)` | 更新操作前 | 可修改 data(原地修改) |
|
||||
| `_serialize(item)` | 列表序列化时 | 自定义返回字段 |
|
||||
| `_serialize_detail(obj)` | 详情序列化时 | 自定义返回字段 |
|
||||
|
||||
## 基类提供的通用方法
|
||||
|
||||
| 方法 | 说明 |
|
||||
|:----|:----|
|
||||
| `get_page(handler)` | 分页查询,返回 R 对象 |
|
||||
| `get_detail(obj_id)` | 查询详情,返回序列化字典或 None |
|
||||
| `add(handler)` | 新增记录,返回 R 对象 |
|
||||
| `update(handler)` | 更新记录,返回 R 对象 |
|
||||
| `delete(handler, ids)` | 单条/批量删除(软删除),返回 R 对象 |
|
||||
| `batch_delete(handler)` | 批量删除(请求体为 ID 数组),返回 R 对象 |
|
||||
| `update_status(handler)` | 更新状态,返回 R 对象 |
|
||||
| `get_options(handler)` | 下拉列表查询,返回 R 对象 |
|
||||
|
||||
## 开发要点
|
||||
|
||||
1. **必须声明 `repo_cls` 和 `model`**:基类所有方法依赖这两个属性
|
||||
2. **`repo_cls` 是类而非实例**:传入 Repository 类,基类自动实例化
|
||||
3. **分页配置按需声明**:`page_like_fields` / `page_eq_fields` / `page_order_by`
|
||||
4. **唯一性校验通过 `unique_fields` 配置**:基类自动处理,无需手写查询
|
||||
5. **删除前校验用 `_before_delete` 钩子**:返回错误字符串中止操作
|
||||
6. **必须创建模块级单例**:`xxx_service = XxxService()`
|
||||
7. **所有方法接收 `handler`(Tornado Handler 实例)**:非 request 对象
|
||||
|
||||
## 总结
|
||||
|
||||
Service 层继承 `BaseService` 获得通用 CRUD 能力,只需声明差异点(`repo_cls`/`model`/`page_like_fields`/`unique_fields`/`serialize_maps`)并覆写钩子方法。必须创建模块级单例,所有方法接收 Tornado Handler 实例。
|
||||
Reference in New Issue
Block a user