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

146 lines
5.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.
# 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 实例。